惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
C
CERT Recently Published Vulnerability Notes
P
Proofpoint News Feed
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)
IT之家
IT之家
Help Net Security
Help Net Security
月光博客
月光博客
N
News and Events Feed by Topic
Cloudbric
Cloudbric
博客园 - 司徒正美
L
LangChain Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tenable Blog
The Register - Security
The Register - Security
The Hacker News
The Hacker News
I
InfoQ
The Last Watchdog
The Last Watchdog
MyScale Blog
MyScale Blog
Schneier on Security
Schneier on Security
WordPress大学
WordPress大学
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
K
Kaspersky official blog
L
LINUX DO - 热门话题
N
News | PayPal Newsroom
F
Fortinet All Blogs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Security @ Cisco Blogs
Recorded Future
Recorded Future
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
C
Cisco Blogs
N
News and Events Feed by Topic
V2EX - 技术
V2EX - 技术
Latest news
Latest news
PCI Perspectives
PCI Perspectives
T
The Blog of Author Tim Ferriss
P
Palo Alto Networks Blog
T
Tor Project blog
Project Zero
Project Zero
云风的 BLOG
云风的 BLOG
Webroot Blog
Webroot Blog
Attack and Defense Labs
Attack and Defense Labs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

蛋蛋之家

SUMIFS和LET函数——让 Excel 自己动起来 Halo 博客晚间卡顿排查记:从"玄学卡顿"到"真凶落网" 我用这个开源项目,把 AI 绘画提示词变成了"代码"——awesome-gpt-image-2 深度体验报告 群晖部署 LX Music Server:浏览器就是你的音乐播放器【详细版】 500道Word题库太痛苦?于是我写了个智能学习平台 别用一个人的奔跑,耗尽两个人的余生——《你凭什么认为我会一直喜欢你呢》 2026 生产级指南:Halo 2.x + PostgreSQL 自动化部署与性能优化手册 从 Typecho 转向 Halo 2.x:全能型 Nginx 架构与 SEO 无损迁移指南 Typecho 迁移 Halo 完整教程:数据库视图解决表前缀 + 自动提取封面图 + 去重检测 我的 CodeBuddy 装备库:218个技能全公开 + 使用心得 为博客添加自定义评论表情 Comment2Bark:Typecho评论推送到Bark插件 又拍云插件 UpyunFile v1.2 更新:修复 Typecho 1.3.0 兼容性问题 手把手修复RSS 403:从PHP警告到Cloudflare拦截的全链路排查 网站被镜像怎么办?2026年反镜像攻防实战指南 VLESS + Reality + Vision:2026 极致隐蔽节点搭建全解析 给OpenList和Alist加上液态玻璃效果,颜值直接拉满! 网页截图瞬间“赛博飞升”?手把手教你根治 Windows HDR 截图发白 群晖 NAS 影音终极方案:Docker Rclone + OpenList 完美挂载 Plex 全攻略 一个简洁高效的SVG图标库 告别重复劳动!一键填充评论的神奇书签脚本 - 蛋蛋之家 解锁思源笔记的隐藏力量:siyuan-patch 深度体验与技术实现 Oracle Cloud 自救指南:旧手机丢失后如何绕过 MFA 重新登录【更新2026年最新政策】 本站已加入“萌国ICP备案”联萌!😄 Excel 月报自动化指南:告别重复劳动,让数据主动为你服务 梦呓:为异地女友准备的2周年惊喜礼物 Typecho 多吉云插件优化:更灵活的存储目录配置 甲骨文云硬盘扩容指南:从50G到200G的“免费午餐”怎么吃? ⏰ 时间同步:当你的服务器开始“穿越”时,如何优雅地把它拉回现实 Typecho 又拍云文件管理插件修改版使用指南:新增自定义目录结构功能 华为鸿蒙6.0回退4.2记录 最近小公主情绪不佳 劳动节的家乡景色 烟台山公园一游 群晖搭建ChatGPT Web 推荐脚本:ChatGPT - 提示选择器 Activation Method for JetBrains Products (English version) JetBrains 系列产品激活方法 疫情三年后再进校园 修复searchEngineJump在谷歌搜索页面不生效问题 事情既然发生了,可以是遗憾,不要去后悔。 侄女的试唱会比赛 新一代图片编码格式测试 省科技馆之行 Typora Windows版破解补丁及主题推荐 在Typora中使用PicList上传图片 域名ICP备案之变更网站 Ubuntu 系统如何使用 root 用户登录 中国联通——让一切自由连不通 如何选购适合的口罩? 今天移动营业厅遇到一个小姐姐,真的好美 它不乐意 如何解决Typecho文章不是Markdown语法创建问题 探手抓住这一天的尾巴,为自己庆生 收到腾讯云自媒体分享计划2月份礼品 尝试百度Spider抓取异常问题 甲骨文DD重装系统及失联救砖教程 终于MrDoc升级v0.8.7成功了 Windows 端口查询及杀死进程 甲骨文实例开通与X-UI安装 国艺花鸟市场的悠闲 在思源笔记中使用群晖Synology C2对象存储服务 MrDoc升级v0.8.7失败 居居的手工作品 Linux系统时间同步命令小结 AList安装指南 宝塔面板降级 v7.7.0 及解除强制绑定手机、免费安装专业版插件的方法 修复群晖Synology Drive client右键菜单缺失问题 Windows11 展开折叠的右键菜单为传统模式 在 Windows 下批量将 Markdown 文档转为 Word 文档 Typecho的一些修改记录 Markdown语法——Mermaid 有两种新方案—CloudFlare官方免费CNAME接入教程 居居的新冠历程 群辉安装Transmission套件、增强汉化WebUI并备份做种列表 群晖 docker 部署思源笔记 Office for Mac 2019 License Installer 公众号通过api发送小程序消息 Windows 10下 iTunes 备份默认存储路径修改 Excel查找返回多个值,并将返回的值放在同一个单元格里面 七牛云测试域名失效后如何下载空间中的文件 入手三星860 evo 500g SSD固态硬盘 分享一套耐看的鼠标指针 如何重置OmniFocus数据库 Office for Mac 2016 License Installer Mac下配置终端+iTerm 2主题 如何制作苹果系统安装U盘 LNMP部署typecho,开启SSL、强制开启https Stylish样式如何设置为特定网址不生效? Typecho插件错误号:42S01的解决方法 电动车被偷了 热火 R150 上手开箱 UltraMon 3.3.0 汉化+注册机 如何用 MWeb 发布 Typecho 文章 测试 Mweb 发布到印象笔记功能 忘记了iPhone访问限制的密码该怎么办? 新玩具KAREE电子烟,先试试 Mac mini 2011 开启Handoff方法 见微知著 浅谈手游创新 PhoneClean Pro授权注册激活码
博客评论自动填充新方案:兼容 Vue/React 响应式绑定与跨架构填充逻辑
吴蛋蛋 · 2026-04-28 · via 蛋蛋之家

我之前分享过一个书签脚本:

https://wuqishi.com/archives/magical-bookmark-script-to-populate-comments-with-one-click

随着最近接触 Halo 2.x 等现代博客系统越来越多,我发现这个老脚本 "失灵" 了。问题根源不再是简单的 "找不到输入框",而是前端框架的响应式绑定机制——你改了 value,框架并不知道,点击提交时数据就被重置了。

为了解决这个问题,在跟 AI 死磕良久,对代码进行了数次重构与逻辑审计之后,最终打磨出了这套全平台通用版

走过路过,瞧一瞧看一看了嘿 ~


脚本适用平台示意
脚本适用平台示意

一、 探究一下为什么评论填充脚本为何失灵

以前的填充脚本在 Typecho 上表现完美,但在 Halo 2.x 或一些现代 Vue/React 主题上,填完后点击提交,信息会瞬间消失,或者啥也没填充上。

这并不是因为找不到元素,而是 "数据绑定" 断了。 现代前端框架(如 Vue 3、React)不再通过读取 DOM 的 value 来获取数据,而是通过监听 input 事件来同步内部状态 。如果你的脚本只是修改了 value 而没有触发相应的事件,框架的内部变量依然是空的,提交时自然会 "穿帮"。

Vue 的 v-model 指令本质上是 :value 绑定与 @input 事件监听器的语法糖 。当用户输入时,input 事件被触发,框架将 event.target.value 同步到内部状态;反之,当状态变化时,框架更新 DOM 的 value。但如果通过脚本直接修改 value而不派发事件,框架的监听器永远不会被触发,导致状态与 DOM 脱节。

各平台架构差异对比

特征类型

代表程序

核心挑战

脚本应对方案

传统 SSR

Typecho / WordPress

DOM 结构固定,无特殊逻辑

标准 ID 匹配 + 快速填充

响应式架构

Halo 2.x / Vue 主题

填入 value 但无法触发生命周期

派发冒泡事件流 (input/change/blur)

异步加载

Hexo (Valine/Waline)

脚本运行瞬间评论框还没渲染

MutationObserver 异步捕获

Web 组件

部分第三方评论插件

存在 Shadow DOM 封装隔离

深度递归穿透搜索


二、 完整代码(详细注释版)

代码中不仅考虑了选择器的覆盖,更核心的是解决了数据同步异步渲染的问题。

核心点

  1. 事件驱动同步:通过触发 inputchangeblur 三重事件,确保 Vue/React 等框架的响应式系统能够捕获到数据变化 。

  2. MutationObserver 异步捕获:针对评论框异步注入的场景(如 Valine、Waline),监听 DOM 变化并在元素出现时自动填充。

  3. Shadow DOM 穿透:递归遍历 shadowRoot,兼容基于 Web Components 的第三方评论系统。

  4. 隐藏域规避:过滤 type="hidden" 的输入框,避免误触反垃圾 "蜜罐" 机制。

  5. 单次执行去重:依赖执行周期内的状态判断,避免对同一元素重复填充。

源代码

有点长,点击打开吧
/*
 * 全平台评论自动填充脚本 (通用增强版 V2.0)
 * 核心:响应式事件同步 + MutationObserver 异步捕获 + 隐藏域规避
 */
(function() {
  // --- [1] 个人信息配置区 ---
  var config = {
    data: {
      n: '吴蛋蛋',              // 你的昵称
      e: '[email protected]',      // 你的邮箱
      w: 'https://wuqishi.com'  // 你的网址(末尾不要留空格)
    },
    // --- [2] 属性选择器规则库 ---
    // 涵盖 Typecho, Halo, WP, Z-Blog 等主流主题特征
    rules: {
      n: ['#author', '#inpName', 'input[name="author"]', 'input[placeholder*="昵称"]'],
      e: ['#mail', '#email', 'input[name="email"]', 'input[placeholder*="邮箱"]'],
      w: ['input[type="url"]', '#url', 'input[name="url"]', 'input[placeholder*="网址"]']
    }
  };

  var filledCount = 0;
  var observer = null;

  /**
   * 执行填充逻辑
   * 返回 boolean:是否成功填充至少一个字段
   */
  function executeFill() {
    var foundThisRound = 0;
    for (var k in config.rules) {
      var selectors = config.rules[k];
      for (var i = 0; i < selectors.length; i++) {
        var el = deepQuery(document, selectors[i]);
        // 核心判定:排除 hidden 蜜罐,确保是可见输入框
        if (el && el.type !== 'hidden' && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA')) {
          el.value = config.data[k];
          // 派发事件:bubbles 保证在 DOM 树中冒泡
          // composed: true 允许事件从 Shadow DOM 内部向外冒泡(若元素位于 shadowRoot 内)
          var evs = ['input', 'change', 'blur'];
          for (var j = 0; j < evs.length; j++) {
            el.dispatchEvent(new Event(evs[j], { bubbles: true, composed: true }));
          }
          filledCount++;
          foundThisRound++;
          break; // 该类目匹配成功即跳出
        }
      }
    }

    if (foundThisRound > 0) {
      showFeedback(filledCount);
      // 填充成功后停止观察,释放性能
      if (observer) { observer.disconnect(); observer = null; }
      return true;
    }
    return false;
  }

  /**
   * 递归穿透 Shadow DOM
   * 普通 querySelector 无法进入 shadowRoot,必须手动下潜
   */
  function deepQuery(root, sel) {
    var el = root.querySelector(sel);
    if (el) return el;
    var all = root.querySelectorAll('*');
    for (var i = 0; i < all.length; i++) {
      if (all[i].shadowRoot) {
        el = deepQuery(all[i].shadowRoot, sel);
        if (el) return el;
      }
    }
    return null;
  }

  /**
   * 初始化:立即执行 + MutationObserver 兜底
   */
  function init() {
    // 立即执行一次
    if (executeFill()) return;

    // 若未找到,监听 DOM 变化(应对异步注入的评论框)
    observer = new MutationObserver(function() {
      if (executeFill() && observer) {
        observer.disconnect();
        observer = null;
      }
    });
    observer.observe(document.body, { childList: true, subtree: true });

    // 10 秒后停止监听,避免长期性能损耗
    setTimeout(function() {
      if (observer) { observer.disconnect(); observer = null; }
    }, 10000);
  }

  /**
   * UI 反馈提示
   */
  function showFeedback(count) {
    var msg = document.getElementById('h-msg') || document.createElement('div');
    msg.id = 'h-msg';
    msg.textContent = '✅ 已填充 ' + count + ' 项字段';
    msg.style.cssText = 'position:fixed;top:20px;right:20px;background:#4CAF50;color:white;padding:12px 24px;border-radius:4px;z-index:999999;font-family:sans-serif;box-shadow:0 2px 10px rgba(0,0,0,0.2);animation:h-fade 3s ease';
    if (!msg.parentNode) document.body.appendChild(msg);
    setTimeout(function() { if(msg.parentNode) msg.parentNode.removeChild(msg); }, 3000);
    if (!document.getElementById('h-style')) {
      var style = document.createElement('style');
      style.id = 'h-style';
      style.textContent = '@keyframes h-fade{0%,100%{opacity:0;transform:translateY(-10px)}15%,85%{opacity:1;transform:translateY(0)}}';
      document.head.appendChild(style);
    }
  }

  // 启动
  init();
})();

三、 可直接使用的书签代码

将上述逻辑压缩成标准 ES5 语法,确保最大兼容性。

操作步骤

  1. 在浏览器书签栏右键 → 添加网页 / 书签

  2. 名称:填入 "自动填表" 或 "一键评论"。

  3. 网址 (URL):完整复制粘贴下方这一行压缩代码:

javascript:(function(){var d={n:'吴蛋蛋',e:'[email protected]',w:'https://wuqishi.com'},r={n:['#author','#inpName','input[name="author"]','input[placeholder*="昵称"]'],e:['#mail','#email','input[name="email"]','input[placeholder*="邮箱"]'],w:['input[type="url"]','#url','input[name="url"]','input[placeholder*="网址"]']},f=0,o=null;function x(){var a=0;for(var k in r){var s=r[k];for(var i=0;i<s.length;i++){var el=q(document,s[i]);if(el&&el.type!=='hidden'&&(el.tagName==='INPUT'||el.tagName==='TEXTAREA')){el.value=d[k];var v=['input','change','blur'];for(var j=0;j<v.length;j++)el.dispatchEvent(new Event(v[j],{bubbles:true,composed:true}));f++;a++;break}}}if(a>0){y(f);if(o){o.disconnect();o=null}return true}return false}function q(root,sel){var e=root.querySelector(sel);if(e)return e;var a=root.querySelectorAll('*');for(var i=0;i<a.length;i++){if(a[i].shadowRoot){e=q(a[i].shadowRoot,sel);if(e)return e}}return null}function init(){if(x())return;o=new MutationObserver(function(){if(x()&&o){o.disconnect();o=null}});o.observe(document.body,{childList:true,subtree:true});setTimeout(function(){if(o){o.disconnect();o=null}},10000)}function y(c){var m=document.getElementById('h-msg')||document.createElement('div');m.id='h-msg';m.textContent='✅ 已填充 '+c+' 项';m.style.cssText='position:fixed;top:20px;right:20px;background:#4CAF50;color:white;padding:12px 24px;border-radius:4px;z-index:999999;font-family:sans-serif;box-shadow:0 2px 10px rgba(0,0,0,0.2);animation:h-fade 3s ease';if(!m.parentNode)document.body.appendChild(m);setTimeout(function(){if(m.parentNode)m.parentNode.removeChild(m)},3000);if(!document.getElementById('h-style')){var s=document.createElement('style');s.id='h-style';s.textContent='@keyframes h-fade{0%,100%{opacity:0;transform:translateY(-10px)}15%,85%{opacity:1;transform:translateY(0)}}';document.head.appendChild(s)}}init()})();

多身份管理技巧

你可以保存多个书签,每个对应不同身份:

只需修改 config.data 里的内容,即可实现 "切号" 自由。


四、 避坑与进阶

1. 为什么填完点击"提交"会消失?

很多老脚本只改了 value,没触发事件。Vue/React 等框架监听 input 事件来同步状态到内部数据层 。本脚本派发 inputchangeblur 三重事件,确保框架状态树与 DOM 同步。

2. composed: true​ 到底有什么用?

这个参数只在事件从 Shadow DOM 内部向外冒泡时生效。如果目标网站没有使用 Shadow DOM,它是无害的空操作;如果使用了,它确保事件能跨出封装边界被父级监听。

3. 异步注入的兜底逻辑

压缩版中包含了 MutationObserver,如果首次执行时评论框还没加载(常见于 Valine、Gitalk),它会监听 DOM 变化并在元素出现时自动触发填充,最多观察 10 秒后自动释放。

4. 如何验证脚本是否生效?

打开浏览器开发者工具(F12)→ Console 面板,点击书签后若看到绿色提示框但未生效,可检查:

  • 输入框的 idname 属性是否匹配规则库

  • 目标站点是否使用了 closed Shadow DOM(无法穿透)

  • 是否处于跨域 iframe 内(无法操作)


五、 这套方案无法覆盖的场景

技术方案的诚实边界,是建立互相信任的基础。以下场景目前无法解决

  1. 跨域 iframe:如 Disqus、部分版本的畅言,将评论框置于与主站不同源的 iframe 中,受浏览器同源策略限制,任何脚本都无法穿透。

  2. Closed Shadow DOM:若第三方组件使用 attachShadow({mode: 'closed'})element.shadowRoot 返回 null,递归穿透失效。

  3. 严格 CSP 限制:若目标站点配置了禁止内联脚本执行的 Content-Security-Policy,书签脚本会被浏览器拦截,无绕过方案。


六、附录:常见问题速查 (FAQ)

Q: 这个脚本安全吗?会不会泄露我的信息?

A: 脚本完全在本地浏览器执行,不发送任何网络请求,你的个人信息不会离开本机。

Q: 为什么不用浏览器自带的自动填充功能?

A: 浏览器自动填充依赖表单识别,对中文博客系统的兼容性较差,且无法处理 Shadow DOM 和异步注入场景。

Q: 脚本支持移动端吗?

A: 移动端浏览器(如 Safari、Chrome)同样支持书签脚本,但操作方式略有不同,需通过 "添加到主屏幕" 或书签栏调用。

Q: 如何为我的自定义主题添加支持?

A: 在 config.rules 中追加对应的选择器即可。例如你的主题昵称框 ID 是 nickName,则添加 '#nickName'n 数组中。


以上,欢迎给我留评论啊 ~