我给掘金写了一个给用户加标签的功能

掘金总有一些人喜欢写水文,每次都因为标题起得好点进去,结果发现啥也不是。也有一些大佬每一篇都是经典,却因为标题过于平平无奇而错过。

(其实写这篇文章的根本原因是总能在评论区看到某个讨厌的爱引战的人。专门写一个脚本告诉自己ta是sb不要和ta生气。

于是,立刻动手,Cursor+油猴脚本,写了一个加标签的功能,让大家一眼就能区分想看的人和讨厌的人。

接下来我会简单讲一下实现,以及如果大家有兴趣如何安装我的油猴脚本。

什么是油猴脚本

油猴又叫篡改猴(Tampermonkey)是一个浏览器扩展程序,支持主流的浏览器,包括 Chrome、Firefox、Safari、Edge 等。

它允许用户使用自定义 JavaScript 脚本,来向网页添加新功能或修改现有功能。通过油猴也可以安装其他用户编写的脚本程序,常见功能比如广告屏蔽、自动签到、批量下载。

编写油猴脚本也特别简单,就像编写一个普通的 JavaScript 代码一样,然后油猴会在指定的网站自动执行我们的代码。

安装扩展程序后,点击 "添加新脚本",就可以进行代码的编写了。

在默认代码中,会生成初始的元数据配置

js 复制代码
// ==UserScript==
// @name         New Userscript -> 脚本名称
// @namespace    http://tampermonkey.net/ -> 脚本命名空间 可以指定你的网站或代码地址
// @version      2025-06-14 -> 版本号
// @description  try to take over the world! -> 脚本描述
// @author       You -> 作者
// @match        https://www.tampermonkey.net/index.php?browser=chrome -> 脚本运行的网址匹配规则
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net -> 脚本图标
// @grant        none -> 需要的权限
// ==/UserScript==

接下来尝试编写一个最简单的脚本,当我们打开掘金网站时,更新页面的背景色为天蓝色。

js 复制代码
// ==UserScript==
// @name         我的第一个油猴脚本
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  这是一个示例脚本
// @author       你的名字
// @match        https://juejin.cn/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    document.body.style.background = 'lightblue';
})();

代码很简单只有一行,但是启用脚本后,刷新一下可以看到掘金的页面已经改变了

油猴脚本就讲这么多,有了这个能力,我们可以开始编写脚本给掘金加标签了。

如何添加标签

想要添加标签,我们要在个人主页添加两个按钮,然后在点击时进行标签的添加。

我们可以通过 URL 来判断当前是否在个人主页时。当我们在个人主页时,URL 链接是这样的 https://juejin.cn/user/3263006241480605。其中最后一段为用户的 id,我们通过匹配 url 路径来来尝试匹配并获取 id 信息。一旦发现是个人主页,就展示点赞和点踩按钮。

js 复制代码
class DOMUtils {
  // ...
  static isUserPage() {
    return window.location.pathname.match(/^\/user\/(\d+)/);
  }
}

// 用户主页标签展示
function displayUserPageTags() {
  const userPageMatch = DOMUtils.isUserPage();
  // 判断是否是用户主页
  if (userPageMatch) {
    // 获取用户 ID
    const userId = userPageMatch[1];
    // 获取用户信息区域DOM
    const userInfoArea = document.querySelector(
      CONFIG.SELECTORS.USER_INFO_AREA
    );
    if (userInfoArea) {
      // 展示标签
    }
  }
}

当添加的标签时,需要把 id 和标签的映射保存起来,这个时候我们就需要油猴的数据存储和读取的权限。

js 复制代码
// @grant        GM_setValue -> 用于保存数据到本地存储
// @grant        GM_getValue -> 从本地存储中读取数据

然后就可以通过 GM_getValueGM_setValue 来读取数据了。使用示例:

js 复制代码
const USER_TAGS_KEY = 'juejin_userTags';
function saveUserTags(userTags) {
  GM_setValue(USER_TAGS_KEY, userTags);
}
function getUserTags() {
  return GM_getValue(USER_TAGS_KEY, {}); // {} 是默认值 没有对应 key 的时候返回
}
console.log(getUserTags()); // {}
saveUserTags({
  3263006241480605: ['小饼干'],
});
console.log(getUserTags()); // {3263006241480605:['小饼干']}

展示标签的时机

这是一个困扰我的问题,因为页面并没有把用户的 id 展示出来,只展示了用户的名字,但是用名字去存储又不合适,名字可以重复,也可以修改,就不能保证标签的正确性了。

我想过通过拦截 XMLHttpRequest 和 fetch 全部请求,因为无论在哪个页面,返回的数据都包含了用户的 id。但是难点在于:

  • 如何知道哪个页面调用了哪个接口
  • 拦截了接口,怎么把接口数据和页面 DOM 对应上

思路困住时,向 AI 寻求解决方案,这件事很神奇,我只是和 Cursor 说了我要解决的问题,它帮我实现了代码,我震惊的发现 AI 实现的逻辑

因为所有展示用户的地方都是链接,点击都会跳转到个人主页,只要在 DOM 中获取 href 属性的值,就可以获取到用户 id 然后再展示用户标签。代码示例:

js 复制代码
class DOMUtils {
  // ...

  // 从 href 中提取用户 ID
  static extractUserIdFromHref(href) {
    const match = href.match(/\/user\/(\d+)/);
    return match ? match[1] : null;
  }
}

// 文章列表标签展示
function displayArticleListTags() {
  // 获取文章列表 DOM
  const articleItems = document.querySelectorAll(
    CONFIG.SELECTORS.ARTICLE_ITEMS
  );

  // 遍历文章列表
  articleItems.forEach((articleItem) => {
    // 查找有 "href" 属性并且值包含 "/user/" 的 a 标签
    const userLink = articleItem.querySelector('a[href*="/user/"]');
    // 如果用户链接存在,则提取用户 ID
    if (userLink) {
      // 根据用户 ID 获取标签 然后操作DOM 添加标签
    }
  });
}

ok 前置条件都搞定了,接下来就是写代码了。这个工作就直接交给 Cursor 来吧。

完整代码逻辑

代码太长,传到了Github 上:juejin-user-tags

为了方便大家理解流程,让 Cursor 梳理了一份流程图。

graph TD %% 初始化流程 Init[脚本初始化] --> CheckState{检查\ndocument.\nreadyState} CheckState -->|loading| AddListener[添加DOMContentLoaded监听] CheckState -->|complete| CreateManager[创建JuejinUserTagManager] AddListener --> CreateManager %% JuejinUserTagManager初始化 CreateManager --> InitManager[初始化主控制器] InitManager --> InitDisplay[初始化TagDisplayManager] InitManager --> InitObserver[初始化PageObserver] InitManager --> AddButtons[添加标签按钮] InitManager --> DisplayTags[显示所有标签] InitManager --> AddStyles[添加样式] %% 标签显示流程 DisplayTags --> CheckArticles[检查文章列表] DisplayTags --> CheckComments[检查评论列表] DisplayTags --> CheckUserPage[检查用户页面] %% 页面监听流程 InitObserver --> CreateMutationObserver[创建MutationObserver] CreateMutationObserver --> ObserveBody[监听document.body] ObserveBody --> HandleMutation[处理DOM变化] HandleMutation --> ShouldUpdate{需要更新?} ShouldUpdate -->|是| UpdateTags[更新标签显示] ShouldUpdate -->|否| Continue[继续监听] %% 用户交互流程 UserAction[用户操作] --> IsUserPage{是否用户页面?} IsUserPage -->|是| ShowButtons[显示标签按钮] ShowButtons --> ClickButton[点击按钮] ClickButton --> ShowModal[显示标签Modal] ShowModal --> SaveTag[保存标签] SaveTag --> TriggerUpdate[触发tagsUpdated事件] TriggerUpdate --> UpdateTags

安装脚本

可以直接把 index.user.js 复制到本地油猴脚本。也可以点击安装脚本

我是小饼干,欢迎大家来给我贴标签。

相关推荐
海云前端5 分钟前
前端写简历有个很大的误区,就是夸张自己做过的东西。
前端
葡萄糖o_o15 分钟前
ResizeObserver的错误
前端·javascript·html
AntBlack16 分钟前
Python : AI 太牛了 ,撸了两个 Markdown 阅读器 ,谈谈使用感受
前端·人工智能·后端
MK-mm34 分钟前
CSS盒子 flex弹性布局
前端·css·html
小小小小宇1 小时前
CSP的使用
前端
sunbyte1 小时前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | AnimatedNavigation(动态导航)
前端·javascript·vue.js·tailwindcss
ifanatic1 小时前
[每周一更]-(第147期):使用 Go 语言实现 JSON Web Token (JWT)
前端·golang·json
烛阴1 小时前
深入浅出地理解Python元类【从入门到精通】
前端·python
米粒宝的爸爸1 小时前
uniapp中vue3 ,uview-plus使用!
前端·vue.js·uni-app
JustHappy1 小时前
啥是Hooks?为啥要用Hooks?Hooks该怎么用?像是Vue中的什么?React Hooks的使用姿势(下)
前端·javascript·react.js