添加自定义css和js(广告屏蔽等)

可自定义css选择器屏蔽页面广告,添加js脚本

当前为 2021-01-10 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         添加自定义css和js(广告屏蔽等)
// @description  可自定义css选择器屏蔽页面广告,添加js脚本
// @namespace    _cus_ad_sp
// @version      1.0.3
// @author       vizo
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js
// @require      https://cdn.jsdelivr.net/npm/vio-utils/utils.js
// @include      /https?:\/\/[^localhost|127.0.0.1|192.168]+/
// @run-at       document-start
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_registerMenuCommand
// @noframes

// ==/UserScript==

;(function() {
  if (vio.isMobile()) return
  let k = GM_getValue(`cus_${location.host}`) || {}
  if (k.css) {
    let css = `<style class="sty9z1p52">${k.css}</style>`
    document.head.insertAdjacentHTML('beforeend', css)
  }
})()
  
GM_addStyle(`
  img {
    display:none !important;
    height: 0 !important;
    overflow: hidden !important;
    pointer-events: none;
  }
  #modal5sn, #modal5sn * {
    margin: 0;
    padding: 0;
    box-sizing: border-box !important;
  }
  #modal5sn {
    width: 28vw;
    height: 68vh;
    min-width: 400px;
    padding: 30px;
    background: #fff;
    border-radius: 3px;
    line-height: 1.5;
    font-size: 12px;
    box-shadow: 0 0 5px #ccc;
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 50050;
    margin: auto;
  }
  #modal5sn .md-wp {
    height: 100%;
    display: flex;
    flex-direction: column;
  }
  #modal5sn .tit1v {
    color: #555;
    font-size: 18px;
    text-align: center;
    margin-bottom: 15px;
  }
  #modal5sn .c7d-item {
    margin-bottom: 10px;
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
  }
  #modal5sn .css-item-xh,
  #modal5sn .js-item-xh,
  #modal5sn .allset-item {
    flex: 1;
  }
  #modal5sn .stiz {
    font-size: 15px;
    color: #555;
    margin-bottom: 3px;
    position: relative;
  }
  #modal5sn .view-all-set {
    color: #09e;
    cursor: pointer;
    user-select: none;
    position: absolute;
    top: 0;
    right: 0;
  }
  #modal5sn .inpy {
    flex: 0 0 auto;
    height: 32px;
    border: 1px solid #ddd;
    color: #555;
    border-radius: 2px;
    padding: 0 10px;
    outline: none;
  }
  #modal5sn .inpy:focus {
    border: 1px solid #c1c1c1;
  }
  #modal5sn .txtr1z {
    flex: 1;
    color: #555;
    padding: 6px;
    overflow-x: hidden;
    overflow-y: auto;
    border-radius: 2px;
    border: 1px solid #ddd;
    font-size: 12px;
    resize: none;
    white-space: pre-line;
    outline: none;
    font-family: Consolas,sans-serif,"Helvetica Neue",Helvetica,"PingFang SC","Microsoft YaHei";
  }
  #modal5sn .txtr1z:focus {
    border: 1px solid #c1c1c1;
  }
  #modal5sn .txtr1z::-webkit-scrollbar {
    width: 4px;
  }
  #modal5sn .txtr1z::-webkit-scrollbar-corner,
  #modal5sn .txtr1z::-webkit-scrollbar-track {
    background-color: #fff;
  }
  #modal5sn .txtr1z::-webkit-scrollbar-thumb {
    background: #fff;
  }
  #modal5sn .txtr1z:hover::-webkit-scrollbar-thumb {
    background: #e1e1e1;
  }
  #modal5sn .txtr1z:hover::-webkit-scrollbar-corner,
  #modal5sn .txtr1z:hover::-webkit-scrollbar-track {
    background-color: #f7f7f7;
  }
  #modal5sn .btn-w {
    margin-top: 5px;
    display: flex;
    flex-direction: row-reverse;
  }
  #modal5sn .btn-w .c5kbtn {
    width: 90px;
    height: 32px;
    border-radius: 2px;
    margin-right: 10px;
    color: #555;
    background-color: #f1f1f1;
    cursor: pointer;
    outline: none;
    border: 0;
  }
  #modal5sn .btn-w .c5kbtn.b1 {
    color: #fff;
    background-color: #09e;
  }
  #modal5sn .btn-w .c5kbtn:first-child {
    margin-right: 0;
  }
  #modal5sn .btn-w .c5kbtn:focus {
    border: 0;
  }
  #modal5sn .btn-w .c5kbtn:hover {
    opacity: 0.9;
  }
`)

const G = {
  html: `
    <div id="modal5sn" v-show="dialog1s">
      <div class="md-wp">
        <div class="tit1v">设置</div>
        <div class="c7d-item">
          <p class="stiz">打开面板快捷键 <span class="view-all-set" @click="hdlViewAllSet">{{ viewSetText }}</span></p>
          <input type="text" class="inpy" v-model="eKey" placeholder="请输入a-z的任意字母">
        </div>
        <div class="c7d-item css-item-xh" v-show="!showAllSet">
          <p class="stiz">添加css(不含style标签)</p>
          <textarea class="txtr1z" v-model="texCssVal" placeholder="请输入css代码"></textarea>
        </div>
        <div class="c7d-item js-item-xh" v-show="!showAllSet">
          <p class="stiz">添加js(不含script标签)</p>
          <textarea class="txtr1z" v-model="texJsVal" placeholder="请输入js代码"></textarea>
        </div>
        <div class="c7d-item allset-item" v-show="showAllSet">
          <p class="stiz">已添加的网站(可删除) {{ addedNum }} 个</p>
          <textarea class="txtr1z" v-model="allAddedStr"></textarea>
        </div>
        <div class="btn-w">
          <button class="c5kbtn b2" @click="hdlCancel">取消</button>
          <button class="c5kbtn b1" @click="hdlSave">保存</button>
        </div>
      </div>
    </div>
  `,
}
const vm = new Vue({
  data() {
    return {
      // 模态框状态
      dialog1s: false,
      // 快捷键名称
      eKey: '',
      showAllSet: false,
      // css代码
      texCssVal: '',
      // js代码
      texJsVal: '',
      // 已添加的网站
      allAddedStr: '',
    }
  },
  computed: {
    viewSetText() {
      return this.showAllSet ? '查看当前网站' : '查看全部网站'
    },
    addedNum() {
      return this.allAddedStr
        .split('\n')
        .filter(v => !!v)
        .length
    },
  },
  watch: {
    eKey(nVal) {
      this.eKey = /[a-z]/.test(nVal) ? nVal.slice(0, 1) : ''
      GM_setValue('cusBKEkey', this.eKey)
    },
    dialog1s(nVal) {
      if (!nVal) {
        this.showAllSet = false
      }
    },
  },
  methods: {
    setGmVal(val) {
      return GM_setValue(`cus_${location.host}`, val)
    },
    getGmVal() {
      return GM_getValue(`cus_${location.host}`) || {}
    },
    hdlSave() {
      if (!this.showAllSet) {
        this.addCss()
        this.addJs()
        this.delEmptyKey()
        this.initAllAdded()
      } else {
        this.updateAllAdded()
      }
      this.dialog1s = false
    },
    hdlCancel() {
      this.dialog1s = false
    },
    addCss() {
      if ( !this.texCssVal.trim() && !Object.keys(this.getGmVal()).length ) {
        return
      }
      let css = `<style class="sty9z1p52">${this.texCssVal}</style>`
      document.head.insertAdjacentHTML('beforeend', css)
      
      this.setGmVal({
        ...this.getGmVal(),
        css: this.texCssVal
      })
      
      Array.from(document.querySelectorAll('.sty9z1p52')).forEach((v, i, y) => {
        if (i !== y.length - 1) {
          v.remove()
        }
      })
    },
    addJs() {
      if ( !this.texJsVal.trim() && !Object.keys(this.getGmVal()).length ) {
        return
      }
      let st = document.createElement('script')
      st.classList.add('js7z1p32')
      st.textContent = this.texJsVal
      document.body.appendChild(st)
      
      this.setGmVal({
        ...this.getGmVal(),
        js: this.texJsVal
      })
      
      Array.from(document.querySelectorAll('.js7z1p32')).forEach((v, i, y) => {
        if (i !== y.length - 1) {
          v.remove()
        }
      })
    },
    updateAllAdded() {
      const gmArr = GM_listValues()
        .filter(v => v.includes('cus_'))
        .map(v => v.slice(4))
      const cArr = this.allAddedStr.split('\n')
      gmArr.forEach(v => {
        if (!cArr.some(c => v === c)) {
          GM_deleteValue(`cus_${v}`)
        }
      })
    },
    // 删除空值key
    delEmptyKey() {
      if (!this.texCssVal && !this.texJsVal) {
        GM_deleteValue(`cus_${location.host}`)
      }
    },
    
    tgCfgDialog() {
      this.dialog1s = !this.dialog1s
    },
    hdlViewAllSet() {
      this.showAllSet = !this.showAllSet
    },
    resetAddCss() {
      this.texCssVal = ''
      this.setGmVal({
        ...this.getGmVal(),
        css: '',
      })
      this.delEmptyKey()
      location.reload()
    },
    resetAddJs() {
      this.texJsVal = ''
      this.setGmVal({
        ...this.getGmVal(),
        js: '',
      })
      this.delEmptyKey()
      location.reload()
    },
    initEvt() {
      window.addEventListener('keydown', e => {
        if (
          !(/text|search|number/.test(e.target.type)) &&
          e.target.tagName !== 'TEXTAREA' &&
          !e.altKey && 
          !e.ctrlKey &&
          e.key === this.eKey
        ) {
          this.tgCfgDialog()
        }
      })
    },
    initEkey() {
      this.eKey = GM_getValue('cusBKEkey') || ''
    },
    initCssJsVal() {
      this.texCssVal = this.getGmVal().css || ''
      this.texJsVal = this.getGmVal().js || ''
    },
    initAllAdded() {
      let gmArr = GM_listValues()
        .filter(v => v.includes('cus_'))
        .map(v => v.slice(4))
      this.allAddedStr = gmArr.join('\n')
    },
    initAddedScript() {
      let js = this.getGmVal().js
      if (js) {
        let st = document.createElement('script')
        st.classList.add('js7z1p32')
        st.textContent = js
        document.body.appendChild(st)
      }
    },
  },
  mounted() {
    this.initEvt()
    this.initEkey()
    this.initCssJsVal()
    this.initAllAdded()
    this.initAddedScript()
  },
})

const initFunc = () => {
  if (vio.isMobile()) return
  document.body.insertAdjacentHTML('beforeend', G.html)
  vm.$mount('#modal5sn')
  GM_registerMenuCommand('打开设置面板', vm.tgCfgDialog)
  GM_registerMenuCommand('清空当前网站添加的CSS', vm.resetAddCss)
  GM_registerMenuCommand('清空当前网站添加的JS', vm.resetAddJs)
}

initFunc()