我现在用的iOS系统。有时候在手机上浏览博客文章,需要评论的时候需要填写“称呼”“邮箱””网站地址“之类的信息。

每次手动填写太麻烦。所以用豆包输入法的“常用语”功能来快捷填入。有些博客自带“记住信息”功能还好,下次不用输了。遗憾的是,部分博客没有这个功能。

我之前用AI写了一个Chrome扩展,可以实现自动填充,只管写评论内容就行。

手机上这个扩展就用不了了。我在手机上尝试了好几个浏览器。Safari浏览器的油猴扩展竟然需要付钱才能用😅

edge和via都支持安装脚本。我嫌edge太丑就用了via。本来是想找以前一个博友自己做的脚本试试,但翻了半天邮箱也没找到。就和DeepSeek的App聊了几个回合,自制了一个填充脚本

在via-设置-脚本,复制进去即可。用法是修改“你的个人信息”注释下面的name,email,url改为自己的就行。脚本的生效方式是在网页打开的瞬间自动填充进去,没有额外的提示,完全无感操作。非常丝滑。比德芙还要丝滑~

我自用了一段时间,大部分博客网站都可以使用。

// ==UserScript==
// @name         博客评论智能填充 (模糊匹配版)
// @namespace    local.blog.smart
// @version      5.0
// @description  智能识别并填充评论区,无视各种魔改名称
// @match        *://*/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';

    // ===== 你的个人信息 =====
    var USER = {
        name: 'Sheep5',
        email: 'me@sheep5.net',
        url: 'https://sheep5.net'
    };

    // 已经填过的框打个标记,防止重复触发
    var MARK = 'data-autofilled-smart';
    var stopped = false;
    var maxTime = 20000; 
    var startTime = Date.now();

    // 智能识别函数
    function detectInputType(el) {
        // 1. 提取这个输入框的所有“指纹”信息并转为小写
        var attrs = (
            (el.name || '') + ' ' +
            (el.id || '') + ' ' +
            (el.className || '') + ' ' +
            (el.placeholder || '') + ' ' +
            (el.getAttribute('aria-label') || '') + ' ' +
            (el.type || '')
        ).toLowerCase();

        // 提取父级容器的文本(很多时候表单是 <div><span>邮箱</span><input></div>)
        var parentText = '';
        if (el.parentElement) {
            parentText = (el.parentElement.innerText || '').toLowerCase().replace(/\n/g, '');
        }
        
        var combined = attrs + ' ' + parentText;

        // 2. 排除干扰项(搜索框、密码、验证码、勾选框等)
        if (['hidden', 'checkbox', 'radio', 'submit', 'button', 'password', 'search'].indexOf(el.type) !== -1) return null;
        if (/搜索|search|密码|password|验证码|captcha/i.test(combined)) return null;
        // 必须是 input,不能是 textarea (留言内容框不需要填)
        if (el.tagName !== 'INPUT') return null;

        // 3. 匹配邮箱 (优先级最高,因为有 type="email" 这个硬核特征)
        if (el.type === 'email' || /邮箱|email|mail|e-mail/i.test(combined)) {
            return 'email';
        }

        // 4. 匹配网站
        if (el.type === 'url' || /网站|网址|主页|博客|website|url|link|site|home/i.test(combined)) {
            return 'url';
        }

        // 5. 匹配昵称
        if (/昵称|称呼|名字|姓名|name|nick|author|username/i.test(combined)) {
            return 'name';
        }

        return null;
    }

    // 兼容 Vue/React 的赋值函数
    function setValue(el, value) {
        if (!el || !value) return false;
        if (el.value && el.value.trim() !== '') return false; // 有内容不覆盖
        if (el.hasAttribute(MARK)) return false;

        try {
            var proto = Object.getPrototypeOf(el);
            var desc = Object.getOwnPropertyDescriptor(proto, 'value');
            if (desc && desc.set) {
                desc.set.call(el, value);
            } else {
                el.value = value;
            }
        } catch (e) {
            el.value = value;
        }

        try {
            el.dispatchEvent(new Event('input', { bubbles: true }));
            el.dispatchEvent(new Event('change', { bubbles: true }));
            el.setAttribute(MARK, 'true');
        } catch (e) {}
        return true;
    }

    function scanAndFill() {
        if (stopped) return;

        var inputs = document.querySelectorAll('input');
        var filledName = false, filledEmail = false, filledUrl = false;

        for (var i = 0; i < inputs.length; i++) {
            var el = inputs[i];
            var type = detectInputType(el);

            if (type === 'name' && !filledName) {
                if (setValue(el, USER.name)) { filledName = true; console.log('智能填充: 昵称'); }
            } else if (type === 'email' && !filledEmail) {
                if (setValue(el, USER.email)) { filledEmail = true; console.log('智能填充: 邮箱'); }
            } else if (type === 'url' && !filledUrl) {
                if (setValue(el, USER.url)) { filledUrl = true; console.log('智能填充: 网址'); }
            }
        }

        // 如果三个框都填上了,或者超时了,就停止监听
        if ((filledName && filledEmail && filledUrl) || (Date.now() - startTime > maxTime)) {
            stopped = true;
            cleanup();
        }
    }

    function cleanup() {
        if (window.__smartTimer) clearInterval(window.__smartTimer);
        if (window.__smartObserver) window.__smartObserver.disconnect();
    }

    // 监听 DOM 变动
    try {
        window.__smartObserver = new MutationObserver(function () {
            scanAndFill();
        });
        window.__smartObserver.observe(document.documentElement || document.body, {
            childList: true,
            subtree: true
        });
    } catch (e) {}

    // 轮询兜底
    window.__smartTimer = setInterval(scanAndFill, 800);
    scanAndFill();

})();