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

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
T
The Exploit Database - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
F
Fox-IT International blog
The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
I
Intezer
P
Privacy & Cybersecurity Law Blog
B
Blog RSS Feed
Latest news
Latest news
小众软件
小众软件
A
Arctic Wolf
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 热门话题
博客园 - 聂微东
B
Blog
T
Troy Hunt's Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
Malwarebytes
Malwarebytes
爱范儿
爱范儿
Recorded Future
Recorded Future
Apple Machine Learning Research
Apple Machine Learning Research
人人都是产品经理
人人都是产品经理
D
Docker
T
Threat Research - Cisco Blogs
MyScale Blog
MyScale Blog
Martin Fowler
Martin Fowler
E
Exploit-DB.com RSS Feed
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
PCI Perspectives
PCI Perspectives
Scott Helme
Scott Helme
N
Netflix TechBlog - Medium
博客园 - 三生石上(FineUI控件)
T
True Tiger Recordings
C
Check Point Blog
Microsoft Azure Blog
Microsoft Azure Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
K
Kaspersky official blog
Security Latest
Security Latest
The Hacker News
The Hacker News
Microsoft Security Blog
Microsoft Security Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Stack Overflow Blog
Stack Overflow Blog
S
Security @ Cisco Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
M
Microsoft Research Blog - Microsoft Research

蛋蛋之家

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 多吉云插件优化:更灵活的存储目录配置 - 蛋蛋之家 - 一枚蛋蛋的自留地
博客评论自动填充新方案:兼容 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()})();

多身份管理技巧

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

书签名称

配置示例

使用场景

一键评论 - 博主

n:'吴蛋蛋', e:'[email protected]'...

日常友链互动

一键评论 - 马甲

n:'匿名网友', e:'[email protected]'...

测试或隐私场景

只需修改 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 数组中。


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