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

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

目前為 2021-01-10 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         添加自定义css和js(广告屏蔽等)
// @description  可自定义css选择器屏蔽页面广告,添加js脚本
// @namespace    _cus_ad_sp
// @version      1.0.5
// @author       vizo
// updateUrl     
// @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|greasyfork]+/
// @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) {
    GM_addStyle(`sty9z1p52 {}\n${k.css}\n`)
  }
})()

GM_addStyle(`
  #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|password|tel|url|email/.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)
      }
    },
    initGMStyleClass() {
      document.querySelectorAll('style').forEach(v => {
        if (!/\w{8}(-\w{4}){3}-\w{12}/.test(v.id)) {
          return
        }
        if (v.textContent.includes('sty9z1p52')) {
          v.classList.add('sty9z1p52')
        }
      })
    },
  },
  mounted() {
    this.initEvt()
    this.initEkey()
    this.initCssJsVal()
    this.initAllAdded()
    this.initAddedScript()
    this.initGMStyleClass()
  },
})

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

initFunc()