Greasy Fork 还支持 简体中文。

掘金沸点过滤器

过滤掉那些看起来很睿智的沸点和伙计

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         掘金沸点过滤器
// @version      0.2.5
// @description  过滤掉那些看起来很睿智的沸点和伙计
// @author       睿智的河水
// @match        *://juejin.im/*
// @namespace    https://greasyfork.org/scripts/388549
// @grant        none
// ==/UserScript==

(function() {
  'use strict'

  const jjStyle = key => {
    if (key.substring(0, 1) === 'V') {
      key = `v-${key.substring(1)}`
    }
    return `
      .jj-block-dialog {
        position: fixed;
        z-index: 9999;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,.25);
      }
      .jj-block-dialog-box {
        position: relative;
        width: 520px;
        background: #fff;
        padding: 20px;
        margin: 8% auto 0;
        border-radius: 5px;
      }
      .jj-block-dialog-box .close {
        position: absolute;
        right: -15px;
        top: -15px;
        width: 26px;
        height: 26px;
        font-size: 26px;
        text-align: center;
        line-height: 26px;
        color: #666;
        background: #fff;
        border-radius: 50%;
        border: 1px solid #ccc;
        transform: rotateZ(45deg);
        cursor: pointer;
        user-select: none;
      }
      .jj-block-dialog-box .label {
        font-size: 14px;
      }
      .jj-block-dialog-box .textarea {
        height: 80px;
        margin: 12px 0;
        padding: 6px;
        color: #333;
      }
      .jj-block-dialog-box .textarea:focus {
        border-color: #007fff;
      }
      .jj-block-dialog-box .button {
        width: 80px;
      }
      .jj-block-dialog-box .tip {
        color: #888;
        margin-left: 12px;
      }
      .block-action[data-${key}] .action-title-box[data-${key}] {
        flex: 1;
        height: 100%;
        font-size: 13px;
        color: #8a93a0;
      }
      .block-panel[data-${key}] {
        position: absolute;
        top: 100%;
        left: 50%;
        margin: 0 0 0 -5.5rem;
        width: 11rem;
        background-color: #fff;
        border: 1px solid #ebebeb;
        border-radius: 2px;
        z-index: 101;
      }
      .block-panel[data-${key}]:after,
      .block-panel[data-${key}]:before {
        content: '';
        position: absolute;
        top: 0;
        left: 50%;
      }
      .block-panel[data-${key}]:before {
        margin: -7px 0 0 -7px;
        border: 7px solid transparent;
        border-top: none;
        border-bottom: 7px solid #ebebeb;
      }
      .block-panel[data-${key}]:after {
        margin: -6px 0 0 -6px;
        border: 6px solid transparent;
        border-top: none;
        border-bottom: 6px solid #fff;
      }
      .block-panel[data-${key}] .block-item[data-${key}] {
        font-size: 13px;
        color: #8a93a0;
        text-align: center;
        padding: 0.5rem 0.9rem;
      }
      .block-panel[data-${key}] .block-item[data-${key}]:not(:last-child) {
        border-bottom: 1px solid #ebebeb;
      }
      .block-panel[data-${key}] .block-item[data-${key}]:hover {
        background-color: #fdfdfd;
      }
    `
  }

  /**
   * 拿到vue
   */
  const JJ = document.querySelector('#juejin').__vue__

  /**
   * 清除空值
   */
  const cleanArray = arr => {
    if (Array.isArray(arr)) {
      return arr.filter(v => v && v.trim())
    }
    return arr
  }

  /**
   * 获取缓存数据
   */
  const getLocal = key => {
    return cleanArray(JSON.parse(localStorage.getItem(key)))
  }

  /**
   * 设置缓存数据
   */
  const setLocal = (key, val) => {
    return localStorage.setItem(key, JSON.stringify(val))
  }

  /**
   * 过滤列表数据
   */
  const filterList = () => {
    const pinItem = document.querySelectorAll('.pin')
    let blockList = getLocal('BLOCK_LIST') || []
    let blockUser = getLocal('BLOCK_USER') || []

    // 遍历当前沸点列表
    for (const v of Array.from(pinItem)) {
      const vInfo = v.__vue__.pin

      if (
        blockList.includes(vInfo.id) ||
        blockUser.includes(vInfo.user.id)
      ) {
        v.classList.add('hidden')
        continue
      }

      v.classList.remove('hidden')

      const action = v.querySelector('.action-box')

      // 注入屏蔽代码
      if (action && !action.classList.contains('is-append')) {
        const blockEl = document.createElement('div')
        const bKey = Object.keys(action.firstElementChild.dataset)[0]
        blockEl.dataset[bKey] = ''
        blockEl.classList = 'block-action action'
        action.appendChild(blockEl)

        const blockTitle = document.createElement('div')
        blockTitle.textContent = '✞ 屏蔽'
        blockTitle.dataset[bKey] = ''
        blockTitle.classList = 'action-title-box'
        blockEl.appendChild(blockTitle)

        const blockPanel = document.createElement('div')
        blockPanel.dataset[bKey] = ''
        blockPanel.classList = 'block-panel shadow hidden'
        blockEl.appendChild(blockPanel)

        blockTitle.onclick = () => {
          blockPanel.classList.toggle('hidden')
        }

        const addElement = (label, cb) => {
          const el = document.createElement('div')
          el.textContent = label
          el.dataset[bKey] = ''
          el.classList = 'block-item'
          el.onclick = cb
          blockPanel.appendChild(el)
        }

        addElement('屏蔽此条', () => {
          blockList.push(vInfo.id)
          setLocal('BLOCK_LIST', blockList)
          v.classList.add('hidden')
        })
        addElement('屏蔽此人', () => {
          blockUser.push(vInfo.user.user_id)
          setLocal('BLOCK_USER', blockUser)
          v.classList.add('hidden')
          filterList()
        })
        addElement('查看已屏蔽', () => {
          blockList = getLocal('BLOCK_LIST') || []
          blockUser = getLocal('BLOCK_USER') || []
          let dialog = document.querySelector('.jj-block-dialog')
          if (dialog) {
            document.body.removeChild(dialog)
          }
          dialog = document.createElement('div')
          dialog.classList = 'jj-block-dialog'
          dialog.innerHTML = `
            <div class="jj-block-dialog-box">
              <span id="jj-block-close" class="close">+</span>
              <label class="label">已屏蔽的沸点</label>
              <textarea id="jj-block-list" class="textarea">${blockList.join(',')}</textarea>
              <label class="label">已屏蔽的用户</label>
              <textarea id="jj-block-user" class="textarea">${blockUser.join(',')}</textarea>
              <button id="jj-block-update" class="button">更新</button>
              <span class="tip">多条数据用逗号(,)隔开,留空则不屏蔽任何沸点和用户</span>
            </div>
          `
          document.body.append(dialog)
          const _ = el => document.querySelector(el) || null
          _('#jj-block-close').onclick = () => {
            document.body.removeChild(dialog)
          }
          _('#jj-block-update').onclick = () => {
            const blockList = _('#jj-block-list').value.split(',')
            const blockUser = _('#jj-block-user').value.split(',')
            setLocal('BLOCK_LIST', blockList)
            setLocal('BLOCK_USER', blockUser)
            document.body.removeChild(dialog)
            filterList()
            JJ.$alertMsg('屏蔽列表已更新')
          }
        })

        if (!document.getElementById('jj-style')) {
          const style = document.createElement('style')
          style.textContent = jjStyle(bKey)
          style.id = 'jj-style'
          document.head.append(style)
        }

        action.classList.add('is-append')
      }
    }
  }

  /**
   * 监听并过滤
   */
  const watchPin = () => {
    const target = document.querySelector('.pin-list-view, .pin-content')
    const config = { childList: true, subtree: true }
    const observer = new MutationObserver(() => {
      filterList()
    })

    if (target) {
      observer.observe(target, config)
    }
  }
  JJ.$router.afterEach(() => {
    watchPin()
  })
  watchPin()
})()