您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
掘金插件 - 赞文章分类功能
当前为
// ==UserScript== // @name 掘金插件 // @namespace https://github.com/zhukunpenglinyutong/Juejin-Plugin // @version 1.0 // @description 掘金插件 - 赞文章分类功能 // @author 朱昆鹏 // @match *://juejin.im/user/* // @require https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js // @grant none // ==/UserScript== let globalData = null; // 全局数据 // 实现一个简单的路由监听(监听跳转是否是主页) window.addEventListener('load', function (e) { var reg = /https:\/\/juejin.im\/user/; if (reg.test(e.target.URL)) init(); // 如果进入主页,触发 }) // ============================================================================================ // ===================== 初始化部分:创建 点赞文章分类,等待点击事件触发 ============================== // ============================================================================================ function init() { //(异步是因为有时候掘金网站加载太慢) setTimeout(() => { createMoreItem(); // 创建 点赞文章分类 div eventBus(); // 点击事件监听(并执行拿取数据 和 创建展示DOM的方法) }, 500) } // 创建 点赞文章分类 div function createMoreItem() { let selectItems = document.querySelectorAll('.nav-item.not-in-scroll-mode .more-panel .more-item') let newA = selectItems[1].cloneNode() // 赋值节点 newA.attributes.removeNamedItem('href') // 删除掉href跳转,因为就当个触发器使用 newA.id = 'jSort' newA.innerText = '文章分类' selectItems[1].parentNode.appendChild(newA) } // 管理事件的函数 function eventBus() { let jSort = document.getElementById('jSort') jSort.addEventListener('click', async event => { let dialogId = document.getElementById('dialogId') if (dialogId) { // 已经点击过分类查看了,只是隐藏到了,这里避免重复拿取,浪费性能 dialogId.style.display = 'inline'; } else { let dataReq = new DataReq() let userId = location.pathname.match(/\w{24}/)[0] let res = await dataReq.getData(userId) // 获取数据 createDOM(res) // 创建展示数据的DOM层 } }) } // ============================================================================================ // =================== 数据处理部分:逻辑处理部分(请求数据 && 处理数据) ============================= // ============================================================================================ // axios配置 let instance = axios.create({ baseURL: 'https://user-like-wrapper-ms.juejin.im/v1/user/', timeout: 30000, headers: { "X-Juejin-Src": "web" } }); // 数据请求类 class DataReq { constructor () { } /** * 请求数据(对外开放) * @param {String} userId */ getData(userId) { console.log('userID', userId) return new Promise (async (resolve, reject) => { // 因为现成的掘金接口,一次只能拿到30个数据,如果点赞很多文章的话,我们需要拼接很多次请求才行 // 思考一:等一个请求返回后,再把page的值增加,直到返回数组为空,不再进行请求,这样是个串行的 // ✅ 思考二:在发送请求之前,先发送一个 page=0&pageSize=0 这时会返回你有多少点赞的文章数量,根据数量这个就能获取到需要发送的次数,这个是并行的 let that = this // 根据返回的数组,建立对应数量的axios请求 let totalArr = await this.getTotal(userId) let aixosArr = totalArr.map(item => instance.get(item)) axios.all(aixosArr) .then(axios.spread( function () { let arr = [] for (let i = 0; i < arguments.length; i++) { arr.push(arguments[i].data.d.entryList) } let resData = that.dataHandle(arr.flat()) resolve(resData) // 经过处理类处理后的数据 })); }) } /** * 请求page=0&pageSize=0 结果用于生成多次axios请求(原因是掘金接口一次拿不到全部点赞数据,上限是30) * (内部使用) * @param { String } 用户ID * @return { Array } ['请求地址一', '', ...] */ getTotal(userId) { return new Promise((resolve, reject) => { instance.get(`${userId}/like/entry?page=0&pageSize=0`) .then(res => { let len = Math.ceil(res.data.d.total/30), arr = []; for (let i = 0; i < len; i++) { arr.push(`${userId}/like/entry?page=${i}&pageSize=30`) } resolve(arr) }) .catch(e => { reject(e) }) }) } /** * 数据处理函数(内部使用)(此处代码写的不好qwq) */ dataHandle (data) { let countedNames = data .map( item => item.tags.map(jtem => jtem.title ) ) .flat(Infinity) .reduce((allNames, name) => { if (name in allNames) { allNames[name]++; } else { allNames[name] = 1; } return allNames; }, {}) // ['Vue.js', 'Vue.js', '...', ...] ===> [ { name: 'Vue.js', num: 6}, {'Jquery': 4}, {} ] let resArr = [] for (let prop in countedNames) { resArr.push({ name: prop, num: countedNames[prop], data: [] }) } resArr.sort((a, b) => b.num - a.num); // 按照数量排序 // 第二部分: // 获取 所有值 let aaa = data.map( item => { return { title: item.title, originalUrl: item.originalUrl, username: item.user.username, objectId: `https://juejin.im/user/${item.user.objectId}`, tags: item.tags.map( j => j.title ) } }) // 整成想要的格式 resArr.forEach( item => { aaa.forEach( jtem => { jtem.tags.some( j => j === item.name) ? item.data.push(jtem) : '' }) }) return resArr } } // ============================================================================================ // ========================= DOM生成层,根据数据生成对应的弹出层和交互 ============================= // ============================================================================================ const createDOM = (res) => { globalData = res // 响应式监听属性,响应点击标签时候的视图切换 let observeData = { select: '' // 当前选中的分类名称 } renderBasic() // 渲染弹出框基本结构 defineReactive(observeData, 'select', observeData.select) // 监听响应式 observeData.select = res[0].name // 初始化,渲染第一个分类中的数据 createDOMEventBus(observeData) // 启动事件监听 } // 渲染弹出框基本结构 function renderBasic() { let dialogMianItem = '' // 根据数据,生成底部导航栏结构 globalData.forEach( item => { dialogMianItem += `<div class="dialog-mian-item" style="position: relative;margin-right: 25px;"> <button class="dialogBtn" style="padding: 9px 15px;font-size: 12px;border-radius: 3px;min-width: 100px;">${item.name}</button> <sup style="position: absolute;top: 0;right: 10px;transform: translateY(-50%) translateX(100%);background-color: #f56c6c;border-radius: 10px;color: #fff;display: inline-block;font-size: 12px;height: 18px;line-height: 18px;padding: 0 6px;text-align: center;white-space: nowrap;"> ${item.num} </sup> </div>` }) // 创建弹出层 let div = document.createElement('div') div.id = 'dialogId' // 模板中展示的内容 div.innerHTML = ` <div class="dialog" style="margin: 15vh auto 50px;width: 60vw;height: 600px;background: #fff;opacity: 1;border-radius: 2px;box-shadow: 0 1px 3px rgba(0,0,0,.3);box-sizing: border-box;"> <div class="dialog-header" style="padding: 20px 20px 10px;line-height: 24px;font-size: 18px;color: #303133;margin-bottom: 15px;display: flex;justify-content: space-between;"> <div>文章分类 <input style="margin-left: 10px;" disabled value="搜索功能8.1日开放" /> </div> <div id="dialog-close" style="cursor: pointer;">X</div> </div> <div class="dialog-mian"> <div class="dialog-mian" style="padding: 0 22px;"> <div class="dialog-mian-lang" style="display: flex;justify-content: space-between;padding-top: 12px;overflow-y: auto;">${dialogMianItem}</div> <div class="dialog-content" style="margin-top: 10px;height: 430px;overflow-y: auto;"> </div> </div> </div> </div> ` let body = document.querySelector('body') div.style = `position: fixed;height: 100vh;width: 100vw;top: 0;left: 0;z-index: 1000;` body.appendChild(div) } // 生成详细文章列表 function createDialogContent(selectName) { let randerData = globalData.filter( item => item.name === selectName)[0].data let dialogContent = document.querySelector('.dialog-content') let dialogContentText = ''; // 具体一行行内容 // 当前点击展示的内容 randerData.forEach(item => { let aStr = '' item.tags.forEach( tag => { aStr += `<a href="javascript:;">${tag} · </a>` }) dialogContentText += ` <div class="dialog-content_item" style="margin: 18px 0px;border-bottom: 1px solid rgba(178,186,194,.15);"> <div class="meta-row"> <a href="${item.objectId}">${item.username}</a> · ${aStr} </div> <div class="title" style="margin-top: 6px;"><a href="${item.originalUrl}" style="font-size: 16px;color: #2E3135;">${item.title}</a></div> </div>` }) dialogContent.innerHTML = dialogContentText } // 事件总线 function createDOMEventBus (observeData) { // 点击切换事件(采用事件冒泡,进行捕获) let btns = document.querySelector('.dialog-mian-lang') btns.addEventListener('click', function (e) { console.log(e) if (e.target.nodeName === 'BUTTON') observeData.select = e.target.textContent; }) // 点击关闭按钮 let dialogClose = document.getElementById('dialog-close') let dialogId = document.getElementById('dialogId') dialogClose.addEventListener('click', function () { console.log('触发') dialogId.style.display = 'none' }) } // ============================================================================================ // ========================== 实现简单数据监听,用来简化DOM操作(朱昆鹏) =========================== // ============================================================================================ // 数据劫持 function defineReactive (obj, key, value) { Object.defineProperty(obj, key, { enumerable: true, configurable: true, get () { return value }, set (newValue) { value = newValue createDialogContent(value) // 更新视图 (生成详细文章列表) } }) }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址