Bilibili-Evolved 组件源码解析:禁用评论区搜索词链接(disable-search-link)
2026/9/19 22:12:13 网站建设 项目流程

Bilibili-Evolved 组件源码解析:禁用评论区搜索词链接(disable-search-link)

【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved

导读

本文以 Bilibili-Evolved 仓库中的「禁用评论区搜索词」组件(disable-search-link)为切入点,完整解析该功能从需求到实现的技术细节:它如何兼容新版(V3)与旧版两种评论区结构、如何借助 Shadow DOM 事件与事件拦截双通道分别处理搜索词链接、如何用!important样式兜底,以及组件的加载/卸载生命周期设计。读完本文,你既能直接上手启用该功能,也能理解 Bilibili-Evolved 评论区组件与 Shadow DOM 观察体系的核心工作原理,为编写同类评论区增强组件提供可复用的实现范式。

一、功能是什么

在哔哩哔哩的评论区中,部分评论内容里包含的搜索词会被渲染为可点击的跳转链接(旧版评论区表现为.jump-link.search-word.icon.search-word元素,新版评论区表现为<a>const name = 'disableCommentsSearchLink' let prevent = false export const component = defineComponentMetadata({ name, displayName: '禁用评论区搜索词', instantStyles: [ { name, style: () => import('./disable-search-link.scss'), important: true, }, { name, style: () => import('./disable-search-link-shadow.scss'), shadowDom: true, }, ], tags: [componentsTags.utils, componentsTags.style], entry: async () => { /* ... */ }, reload: () => { prevent = true }, unload: () => { prevent = false }, })

几个值得注意的元数据细节:

  • instantStyles与两套样式:组件声明了两份即时加载的样式。第一份 disable-search-link.scss 作用于普通 DOM,并标记important: true(生成规则时自动追加!important);第二份 disable-search-link-shadow.scss 设置了shadowDom: true,用于注入到 Shadow DOM 内部——这是新版评论区(Web Component + Lit 渲染)所必需的。
  • tags归属:组件被归类为utils(工具)与style(样式)两类标签,说明它本质上是"以样式为主、辅以事件拦截"的增强组件,在设置面板中按这两个标签均可检索到。
  • 模块级状态prevent:组件使用模块级布尔变量prevent作为"是否启用拦截"的开关,由entry(置为true)、reload(重新置为true)、unload(置为false)三者协同维护,避免重复监听。

三、前置基础:Bilibili-Evolved 的评论区抽象

要理解该组件的实现,需要先了解仓库中评论区的抽象体系。src/components/utils/comment-apis.ts对外暴露了统一的遍历 API(comment-apis.ts):

/** 为每一个评论区执行操作 */ export const forEachCommentArea = (callback: CommentAreaCallback) => { commentAreaManager.forEachCommentArea(callback) }

其底层CommentAreaManager通过allMutations(全局 MutationObserver)监听整个文档,识别选择器.bili-comment, .bb-comment, bili-comments匹配的节点作为评论区(comment-area-manager.ts),并交由工厂函数getCommentArea分派到具体实现(comment-area.ts):

export const getCommentArea = (element: HTMLElement): CommentArea => { if (CommentAreaV3.isV3Area(element)) { return new CommentAreaV3(element) } if (CommentAreaV2.isV2Area(element)) { return new CommentAreaV2(element) } return new CommentAreaV1(element) }

由此可知仓库将评论区划分为三代:

版本判定方式结构特点
V3element.tagName.toLowerCase() === 'bili-comments'新版 Web Component,内容渲染在 Shadow DOM 内,使用 Lit 框架(见 areas/v3.ts)
V2isV2Area(element)旧版结构(.bili-comment等),DOM 直接可见
V1兜底更早期的评论区结构

「禁用评论区搜索词」组件的entry正是基于area instanceof CommentAreaV3的判断,将新版与旧版评论区拆成两条完全不同的处理路径。

四、核心实现:两条处理路径

4.1 新版评论区(V3):Shadow DOM 内的属性剥离

新版评论区使用 Web Component,其内部 DOM 位于 Shadow Root 中,普通 MutationObserver 与事件委托无法直接触达。组件针对 V3 的路径(index.ts):

const isV3Area = area instanceof CommentAreaV3 if (isV3Area) { area.commentAreaEntry.addEventListener( ShadowRootEvents.Updated, (e: CustomEvent<MutationRecord[]>) => { const records = e.detail records.forEach(record => { record.addedNodes.forEach(node => { const isCommentLink = node instanceof HTMLAnchorElement && node.getAttribute('data-type') === 'search' if (!isCommentLink) { return } node.removeAttribute('href') node.removeAttribute('target') }) }) }, ) }

这里依赖两个关键设施:

  1. ShadowRootEvents.Updated:这是仓库 shadow-root 模块自定义的 DOM 事件(见 v3.ts 中同类事件的使用方式),其detail携带MutationRecord[],由ShadowDomObserver在监听 Shadow DOM 变更时派发。组件监听该事件即可感知 V3 评论区内部的节点增删,无需自行观察 Shadow Root。
  2. data-type="search"特征:新版评论区渲染搜索词链接时,会在<a>元素上标记data-type="search"。组件以此作为唯一判定条件,命中后直接执行removeAttribute('href')removeAttribute('target')——href被移除后链接不再可跳转,target被移除后即使残留样式也不会新开标签页。

这种"观察新增节点 + 特征属性判定 + 属性剥离"的方式是典型的新版评论区处理范式,同类组件(如 copy-link)也遵循forEachCommentArea+ Shadow DOM 事件的架构。

4.2 旧版评论区(V1/V2):事件拦截

旧版评论区没有 Shadow DOM 隔离,搜索词链接是普通可点击元素。组件使用preventEvent在捕获阶段拦截点击(index.ts):

preventEvent(area.element, 'click', e => { if (!(e.target instanceof HTMLElement) || !prevent) { return false } const element = e.target as HTMLElement if ( ['.jump-link.search-word', '.icon.search-word'].some(selector => element.matches(selector), ) ) { return true } return false })
  • 选择器集合'.jump-link.search-word'是旧版评论区搜索词跳转链接的 class 组合;'.icon.search-word'则对应其附带的小图标(放大镜图标),两者都会被拦截。
  • 回调语义preventEvent的回调返回true表示阻止该事件(阻止默认行为与冒泡),返回false表示放行。这里通过prevent开关兜底——组件卸载后即便回调残留,也会因prevent === false而放行事件,保证卸载干净。

4.3 两条路径的对比

维度V3(新版)V1/V2(旧版)
技术手段监听ShadowRootEvents.Updated,操作MutationRecordpreventEvent捕获阶段拦截click
判定依据node instanceof HTMLAnchorElement &&>.search-word { &.icon { display: none !important; } // 需要比夜间模式的优先级高 .reply-warp .reply-item &.jump-link { color: inherit !important; cursor: text !important; } }
  • 隐藏放大镜图标(.search-word.icon);
  • .jump-link的颜色改为inherit(跟随正文)、鼠标指针改为cursor: text,并注明"需要比夜间模式的优先级高"——即必须用!important压过夜间模式等主题样式的干扰。

Shadow DOM 样式(disable-search-link-shadow.scss):

:host(bili-rich-text) { #contents a[data-type='search'] { color: inherit !important; cursor: inherit !important; display: contents !important; img { display: none; } } }
  • 通过:host(bili-rich-text)限定作用于新版评论区富文本宿主;
  • a[data-type='search']统一继承颜色与光标、以display: contents消除其作为链接盒子的干扰,并隐藏内部的img图标。

可见该组件在"功能上剥离跳转"与"视觉上还原纯文本"两个层面做了双保险,即使某条路径(如新版评论区的事件未及时触发)暂时失效,样式兜底也能保证视觉上不再呈现为可点击链接。

六、生命周期与卸载安全性

组件通过三个钩子维护状态:

entry: async () => { prevent = true /* 注册监听 */ }, reload: () => { prevent = true }, unload: () => { prevent = false },
  • entry:首次启用时置prevent = true并注册各评论区的监听器;
  • reload:设置面板中调整相关配置后组件重载,重新置prevent = true
  • unload:禁用组件时置prevent = false,使旧版评论区的preventEvent回调形同虚设(事件不再被阻止),配合CommentAreaManager对移除评论区的清理逻辑(见 comment-area-manager.ts),实现无残留卸载。

七、如何启用与验证

该组件随 Bilibili-Evolved 主脚本打包发布,用户无需单独安装:

  1. 在哔哩哔哩页面打开 Bilibili-Evolved 的设置面板;
  2. 在「评论区」相关分类下,或在搜索框输入禁用评论区搜索词(英文标识disableCommentsSearchLink)找到该组件;
  3. 开启开关后刷新评论或滚动加载更多评论,即可看到效果:原搜索词不再可点击跳转,颜色与光标与正文一致。

验证要点(供开发与回归测试参考):

  • 旧版评论区:检查.jump-link.search-word元素点击后是否仍触发跳转(应不跳转),图标是否隐藏;
  • 新版评论区:检查 Shadow DOM 内a[data-type='search']hreftarget属性是否被移除;
  • 启用夜间模式等主题后,确认搜索词颜色仍与正文一致(依赖!important兜底规则);
  • 切换组件开关(reload/unload),确认卸载后点击行为恢复、无重复监听报错。

八、总结与可复用经验

「禁用评论区搜索词」是一个小而完整的评论区增强组件范本,其可复用的工程经验包括:

  1. 双通道兼容:通过area instanceof CommentAreaV3分流,Shadow DOM 场景用ShadowRootEvents.Updated+ 属性剥离,传统 DOM 场景用preventEvent事件拦截,一套组件同时覆盖两代评论区;
  2. 特征属性判定:以data-type="search".search-word等稳定的标记作为识别依据,而非脆弱的文本内容匹配;
  3. 功能与样式分离兜底:事件/属性层负责"不可跳转",SCSS 层(含 Shadow DOM 注入)负责"不像链接",并以!important对抗主题优先级;
  4. 状态开关式卸载:用模块级prevent布尔值让卸载后的回调自动失效,规避重复监听与泄漏。

参考实现文件:组件入口 index.ts、普通样式 disable-search-link.scss、Shadow 样式 disable-search-link-shadow.scss、评论区抽象 comment-apis.ts 与 comment-area-manager.ts。

【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询