openAny 示例大全

ctrl+alt+x 只显示文字外观窗口一部分

image

openAny.setKeymap('ctrl+alt+x', async (event, {newSetStyle})=>{
    const setStyle = newSetStyle();
    // 设置样式  
    setStyle(`.protyle-font > *:not(:nth-child(7),:nth-child(8)):not(:last-child) {
       display:none;
    }`);
    // 等待外观窗口出现
    await openAny.getEl('.protyle-util:not(.fn__none)');
    // 等待外观窗口关闭
    await openAny.getEl('.protyle-util.fn__none', null, -1);
    // 删除样式,不影响后续操作
    setStyle('');
});

alt+z 给文字添加指定颜色和背景色

openAny.setKeymap('alt+z', (event)=>{event.preventDefault();openAny.press('ctrl+alt+x', document.activeElement).clicks('.protyle-util [style="color:var(--b3-font-color9)"]', '.protyle-util [style="background-color:var(--b3-font-background6)"]').invoke(()=>openAny.queryEl('.protyle-util:not(.fn__none)')?.classList?.add('fn__none'))});

打开代码片段窗口

openAny.clicks('#barWorkspace', '[data-id="config"]', '[data-name="appearance"]', '#codeSnippet', '[data-key="dialog-setting"] svg.b3-dialog__close');

打开设置窗口

openAny.click('#barWorkspace').click('[data-id="config"]');
// 或
openAny.pressByKeymap('config');

模式切换(预览和所见即所得切换,按ctrl+alt+7即可)

setTimeout(()=>{
    openAny.addKeymap('alt+meta+7', ()=>{
        const isPreview = document.querySelector('.protyle-preview:not(.fn__none) .protyle-preview__action');
        setTimeout(()=>{if(!isPreview) openAny.press('alt+meta+9');}, 50);
    });
}, 1500);

ctrl+shif+p 全局搜索仅搜文档(不影响原有搜索状态)

// ctrl+shif+p 全局搜索仅搜文档(不影响原有搜索状态)
(async ()=>{
    // 等待openAny加载完毕  
    await waitFor(() => typeof openAny !== 'undefined');
    // 注册快捷键
    const ctrl = navigator.platform.indexOf("Mac") > -1 ? 'meta' : 'ctrl';
    openAny.setKeymap(`shift+${ctrl}+p`, async (event, {getSelectedText}) => {
      openAny
        .press(`${ctrl}+p`) // 打开搜索框
        .click("#searchFilter") // 点击类型过滤按钮
        .input(getSelectedText(), "#searchInput") // 搜索框置空
        .invoke(async ({sleep,whenElementRemoved}) => {
          // 【注意】invoke内部建议用新的OpenAny对象,防止用await时与上层链相互等待造成死锁
          const openAny = new OpenAny();
          // 获取当前的文档类型
          const oldTypes = siyuan?.storage['local-searchdata']?.types;
          // 查询所有文档类型,仅保留文档类型打开,其他全关闭
          openAny
            .queryElAll('[data-key="dialog-searchtype"] [type="checkbox"]')
            .forEach(async (checkbox) =>
              checkbox.matches('[data-type="document"]')
                ? !checkbox.checked && checkbox.click()
                : checkbox.checked && checkbox.click()
            );
          // 点击确定按钮
          openAny.click('[data-key="dialog-searchtype"] .b3-dialog__action .b3-button--text')
          await sleep(100); // 等待100ms
          openAny.focus("#searchInput"); // 聚焦搜索框
          // placehoder
          openAny.queryEl('#searchInput').placeholder = '请输入文档标题';
          // 等待搜索对话框被关闭
          whenElementRemoved('[data-key="dialog-globalsearch"]', ()=>{
            // 恢复原本的文档类型
            if(oldTypes) siyuan.storage['local-searchdata'].types = oldTypes;
          });
        });
    });
    function waitFor(conditionFn, timeoutMs=5000) {
      return new Promise((resolve, reject) => {
        const start = Date.now();
        const check = () => {
          if(typeof conditionFn === 'string') 
              conditionFn = () => document.querySelector(conditionFn);
          const result = conditionFn();
          if (result) resolve(result);
          else if (Date.now() - start > timeoutMs) reject();
          else requestAnimationFrame(check); // 利用浏览器刷新周期
        };
        check();
      });
    }
})();

快速输入,灵感输入

// 快速输入,灵感记录等
(async ()=>{
    // 请填写灵感即将保存的文档ID
    const captureDocId = '20250307013535-lreu6jb';

    // 是否按回车键提交
    // 当为 true 时,回车键提交,shift+回车 换行
    // 当为 false 时,回车换行,ctrl+回车 提交
    const enterSubmit = true;

    // 输入框显示行数,默认3行,当行数是1时,无法换行,同时始终回车提交
    const inputLines = 3;

    // 等待openAny加载完毕  
    await waitFor(() => typeof openAny !== 'undefined');
    // 注册快捷键
    openAny.setKeymap("alt+i", async (event, {fetchSyncPost, showInputBox}) => {
        const input = await showInputBox("", "", "", inputLines, enterSubmit);
        if(!input) return;
        const result = await fetchSyncPost('/api/block/insertBlock', {
            "dataType": "markdown",
            "data": getFormattedDateTime() + "\n{: style=\"color:#989898;\"}\n" + input + "\n---",
            "nextID": "",
            "previousID": "",
            "parentID": captureDocId
        });
        console.log(result);
    });

    function getFormattedDateTime() {
        const now = new Date();
        // 获取年、月、日、时、分、秒
        const year = now.getFullYear(); // 年
        const month = String(now.getMonth() + 1).padStart(2, '0'); // 月(注意月份从 0 开始,需要加 1)
        const day = String(now.getDate()).padStart(2, '0'); // 日
        const hours = String(now.getHours()).padStart(2, '0'); // 时
        const minutes = String(now.getMinutes()).padStart(2, '0'); // 分
        const seconds = String(now.getSeconds()).padStart(2, '0'); // 秒
        // 拼接成字符串
        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    }
    function waitFor(conditionFn, timeoutMs=5000) {
      return new Promise((resolve, reject) => {
        const start = Date.now();
        const check = () => {
          if(typeof conditionFn === 'string') 
              conditionFn = () => document.querySelector(conditionFn);
          const result = conditionFn();
          if (result) resolve(result);
          else if (Date.now() - start > timeoutMs) reject();
          else requestAnimationFrame(check); // 利用浏览器刷新周期
        };
        check();
      });
    }
})();


快速打开(支持搜索,翻译,ai搜索,常用工具快捷打开,打开常用文档,打开本地工具等)

// 快速打开自定义功能
// see https://ld246.com/article/1745488922117
// version 0.0.2
// 0.0.2 增加快捷键支持,把思源命令面板的命令移植过来
// 使用帮助
// 建议把代码放到runjs插件的代码块中方便修改和添加菜单项(当然直接把该代码放到js代码片段中也行,代码片段修改后需要刷新页面)
// 然后,把下面的这行代码放到js代码片段中加载时运行即可(注意,外部调用runjs代码块,先要给块命名,然后保存为可调用的方法)
// runjs调用 runJs.plugin.call('quickOpen')
// runjs中修改代码后,只需点击「块菜单——>Run JS——> 运行代码」即可
//                  或将光标聚焦在代码块中,然后按 alt + F5 即可运行当前的代码块
// 如何添加新菜单?
// 只需要“自定义菜单区 开始”和“自定义菜单区 结束”直接添加 addMenu('菜单名', ()=>{})即可
// 比如:addMenu('demo1', (event, functions, option, selection)=>{alert('demo1')}, 'D', 'shortcut'); 这里第三个参数D代表当菜单出现时按D键直接选中demo1这个菜单
(async (menus = [], pressKey = '' /* 👈修改快捷键可在这里修改pressKey,默认ctrl+; 修改后pressKey后需要刷新页面 */)=>{
    ///////////////////////////////// 自定义菜单区 开始 /////////////////////////////////
    // 打开本代码片编辑窗口
    addMenu('打开本代码片编辑窗口', (event, {getProtyleEl, showErrorMessage}) => {
        // 如果在runjs代码块中,设置这个代码块的可调用方法名,如果不在runjs中保持空或注释即可
        const runjsCallableName = 'quickOpen';
  
        // 如果在代码片段中,设置这个代码片段的名字,如果不在代码片段中保持空或注释即可
        const snippetName = '快速打开自定义功能';
  
        // 当二者都配置的话,runjs优先(代码片段修改代码后需要刷新页面,runjs只需要按alt+f5即可)
        if(typeof runjsCallableName !== 'undefined' && runjsCallableName) {
            const codeBlockId = window.siyuan.ws.app.plugins.find(item=>item.name==='sy-run-js')?.data["Callable.json"]?.quickOpen;
            if(!codeBlockId) showErrorMessage('没有找到'+runjsCallableName+'的代码块');
            window.open('siyuan://blocks/'+codeBlockId);
        } else {
            openAny.clicks('#barWorkspace', '[data-id="config"]', '[data-name="appearance"]', '#codeSnippet', '[data-key="dialog-setting"] svg.b3-dialog__close', '[data-type="js"]').input(typeof snippetName === 'undefined' ? '' : snippetName, '[data-action="search"][data-type="js"]');
        }
    }, 'E');

    // 移动当前文档到
    addMenu('移动当前文档到', (event, {getProtyleEl}) => {
        openAny.click('[data-type="doc"]', getProtyleEl()).click('[data-name="titleMenu"] button[data-id="move"]');
    }, 'M');
  
    // Bing搜索
    addMenu('Bing搜索', (event, {getSelectedText}) => {
        // 搜索引擎URL,%s% 是搜索关键词
        const searchUrl = 'https://cn.bing.com/search?q=%s%&form=QBRE';
        window.open(searchUrl.replace('%s%', getSelectedText()));
    }, 'B');
  
    // 问DeepSeek
    addMenu('问DeepSeek', (event, {getSelectedText}) => {
        // ai引擎URL,%s% 是查询关键词,支持deepseek-r1
        const aiUrl = 'https://chat.baidu.com/search?word=%s%';
        window.open(aiUrl.replace('%s%', getSelectedText()));
    }, 'D');
  
    // 打开翻译
    addMenu('打开翻译', (event, {getSelectedText}) => {
        // 翻译引擎URL,%s% 是翻译关键词
        const fanyiUrl = 'https://fanyi.baidu.com/mtpe-individual/multimodal?query=%s%';
        window.open(fanyiUrl.replace('%s%', getSelectedText()));
    }, 'T');
  
    // 打开查词
    addMenu('打开查词', (event, {getSelectedText}) => {
        const url = 'https://www.iciba.com/word?w=%s%';
        window.open(url.replace('%s%', getSelectedText()));
    });
  
    // 打开设置
    addMenu('打开设置', (event, {}) => {
        openAny.pressByKeymap('config');
    });
  
    // 打开日记
    addMenu('打开日记', (event, {}) => {
        // 在这里输入你想在哪个笔记本中打开今日日记
        const noteBookName = '我的笔记';
        // 这里用wwhenExist先等待指定元素出现,否则需要在do内调用 await new OpenAny().whenExist()等待目标出现
        openAny.click('#barWorkspace').whenExist('[data-name="barWorkspace"]').do(()=>{
            const subMenuItems = [...openAny.queryElAll('[data-id="dailyNote"] .b3-menu__label')];
            const notebutton = subMenuItems.find(item => item.textContent === noteBookName)?.closest('button.b3-menu__item');
            // 返回链元素,供下一个链click调用,也可以直接在这里click,不用再次调用下一个链click
            return notebutton;
        }).click();
    });
  
    // 打开集市
    addMenu('打开集市', (event, {}) => {
        openAny.clicks('#barWorkspace', '[data-id="config"]', '[data-name="bazaar"]');
    });
  
    // 打开代码片段
    addMenu('打开代码片段', (event, {}) => {
        openAny.clicks('#barWorkspace', '[data-id="config"]', '[data-name="appearance"]', '#codeSnippet', '[data-key="dialog-setting"] svg.b3-dialog__close');
    }, 'S');
  
    // 打开快捷键设置
    addMenu('打开快捷键设置', (event, {}) => {
        openAny.clicks('#barWorkspace', '[data-id="config"]', '[data-name="keymap"]');
    });
  
    // 打开搜索
    addMenu('打开思源搜索', (event, {}) => {
        openAny.press('alt+p');
    });
  
    // 打开仅搜索文档
    addMenu('打开仅搜索文档', (event, {}) => {
        // 请参考 ctrl+shif+p 全局搜索仅搜文档,然后把这个快捷键填尽量
        openAny.press('ctrl+shif+p');
    }, 'P');

    // 模式切换
    addMenu('模式切换', (event, {}) => {
        const isPreview = document.querySelector('.protyle-preview:not(.fn__none) .protyle-preview__action');
        if(!isPreview) openAny.press('alt+meta+9'); else openAny.press('alt+meta+7');
    }, '7');
  
    // 打开链滴
    addMenu('打开链滴', (event, {}) => {
        window.open('https://ld246.com');
    });
  
    // 打开我的博客
    addMenu('打开我的博客', (event, {}) => {
        window.open('https://pipe.b3log.org/blogs/wilsons');
    });
  
    // 打开思源工作空间
    addMenu('打开思源工作空间', (event, {showFileInFolder}) => {
        showFileInFolder(window.siyuan.config.system.workspaceDir);
    });
  
    // 打开计算器
    addMenu('打开计算器', (event, {runCmd, isMac}) => {
        let cmd = `start calc`;
        if(isMac()) cmd = `open -a Calculator`;
        runCmd(cmd);
    }, 'C');
  
    // 字母大小写转换
    addMenu('字母大小写转换', (event, {getEditor}, option, {selectedText, selection, range}) => {
        let text = selectedText;
        if(/[a-z]/.test(text)) {
            text = text.toUpperCase();
        } else {
            text = text.toLowerCase();
        }
        // 替换选中的文本
        range.deleteContents();
        range.insertNode(document.createTextNode(text));

        // 恢复选中范围
        selection.removeAllRanges();
        selection.addRange(range);
        //const editor = getEditor();
        //openAny.sendText(text, editor);
    });

    ///////////////////////////////// 自定义菜单区 结束 /////////////////////////////////

    // 等待openAny加载完毕  
    await waitFor(() => typeof openAny !== 'undefined');

    // 生成菜单列表
    const handler = async (event, functions)=>{
        event.preventDefault();
        const selection = window.getSelection();
        const range = selection.getRangeAt(0);
        const selectedText = selection.toString();
        const lastSelected = await getStorageVal('local-quickopen-selected');
        if(lastSelected) {
            const lastSelectedItem = menus.find(item=>item.selected);
            if(lastSelectedItem) lastSelectedItem.selected=false;
            const selectedItem = menus.find(item=>item.label===lastSelected);
            if(selectedItem) selectedItem.selected=true;
        }
        functions.whenElementExist('.open-any-menu-title:not([data-reward="true"])').then((title)=>{
            const search = title.querySelector('.open-any-menu-search');
            if(search) {
                search.style.width = 'calc(100% - 74px)';
                generateReward(title);
                title.dataset.reward = true;
            }
        });
        const selectedOption = await functions.showOptionsMenu(menus, {width:'min(800px, 100%)',maxWidth:'min(1000px, 100%)', height:'min(800px, calc(100% - 80px))', maxHeight:'min(800px, calc(100% - 80px))', search:true, menuItemStyle: 'text-align:left'});
        if (selectedOption !== null) {
            if(typeof selectedOption.callback === 'function') {
                selectedOption.callback(event, functions, selectedOption, {selectedText, selection, range});
                setStorageVal('local-quickopen-selected', selectedOption.label);
            } else {
                alert(selectedOption.callback+' 不是有效的函数');
            }
        }
    };
    pressKey = pressKey || (openAny.fn.isMac() ? 'meta+;' : 'ctrl+;');
    openAny.removeKeymap(pressKey); // 注意,这里未提供callback时,会删除同名的所有监听
    openAny.addKeymap(pressKey, handler);

    // 把命令面板的命令移植过来
    // see https://github.com/siyuan-note/siyuan/blob/e47b8efc2f2611163beca9fad4ee5424001515ff/app/src/boot/globalEvent/command/panel.ts#L49
    Object.keys(window.siyuan.config.keymap.general).forEach((key) => {
        let keys;
        if (isMobile()) {
            keys = ["addToDatabase", "fileTree", "outline", "bookmark", "tag", "dailyNote", "inbox", "backlinks",
                "dataHistory", "editReadonly", "enter", "enterBack", "globalSearch", "lockScreen", "mainMenu", "move",
                "newFile", "recentDocs", "replace", "riffCard", "search", "selectOpen1", "syncNow"];
        } else {
            keys = ["addToDatabase", "fileTree", "outline", "bookmark", "tag", "dailyNote", "inbox", "backlinks",
                "graphView", "globalGraph", "closeAll", "closeLeft", "closeOthers", "closeRight", "closeTab",
                "closeUnmodified", "config", "dataHistory", "editReadonly", "enter", "enterBack", "globalSearch", "goBack",
                "goForward", "goToEditTabNext", "goToEditTabPrev", "goToTab1", "goToTab2", "goToTab3", "goToTab4",
                "goToTab5", "goToTab6", "goToTab7", "goToTab8", "goToTab9", "goToTabNext", "goToTabPrev", "lockScreen",
                "mainMenu", "move", "newFile", "recentDocs", "replace", "riffCard", "search", "selectOpen1", "syncNow",
                "splitLR", "splitMoveB", "splitMoveR", "splitTB", "tabToWindow", "stickSearch", "toggleDock", "unsplitAll",
                "unsplit"];
            if (!isBrowser()) {
                keys.push("toggleWin");
            }
        }
        if (keys.includes(key)) {
            addMenu(window.siyuan.languages[key], (event, functions, option, selection)=>runSiyuanCommand(key, '', event, functions, option, selection), '', !isMobile()?window.siyuan.config.keymap.general[key].custom:'', window.siyuan.languages[key]);
        }
    });
    Object.keys(window.siyuan.config.keymap.editor.general).forEach((key) => {
        if (["switchReadonly", "switchAdjust"].includes(key)) {
            addMenu(window.siyuan.languages[key], (event, functions, option, selection)=>runSiyuanCommand(key, '', event, functions, option, selection), '', !isMobile()?updateHotkeyTip(window.siyuan.config.keymap.editor.general[key].custom):'', window.siyuan.languages[key]);
        }
    });
    window.siyuan.ws.app.plugins.forEach(plugin => {
        plugin.commands.forEach(command => {
            addMenu(`${plugin.displayName}: ${command.langText || plugin.i18n[command.langKey]}`, (event, functions, option, selection)=>runSiyuanCommand(command, 'plugin', event, functions, option, selection), '', !isMobile()?updateHotkeyTip(command.customHotkey):'', `${plugin.displayName}: ${command.langText || plugin.i18n[command.langKey]}`);
        });
    });
  
    // 生成拼音和拼音首字母
    setTimeout(async ()=>{
        let pinyinCache = await getFile('/data/storage/quickopen_pinyin_catche.json') || '{}';
        pinyinCache = JSON.parse(pinyinCache);
        if(pinyinCache.code && pinyinCache.code !== 0) pinyinCache = {};
        let hasNewCache = false;
        for (const menu of menus) {
            try {
                const words = encodeURIComponent(menu.label);
                if(!pinyinCache[menu.label]) pinyinCache[menu.label] = {};
                // 生成汉字拼音
                let pinyin = pinyinCache[menu.label]?.pinyin;
                if(!pinyin) {
                    pinyin = await (await fetch('https://tools.getquicker.cn/api/Chinese/GetPinyin?source='+words+'&tone=false&forName=false')).text();
                    if(pinyin) {
                        pinyinCache[menu.label].pinyin = pinyin;
                        hasNewCache = true;
                    }
                }
                if(pinyin) menu.pinyin = pinyin;
                // 生成拼音首字母
                let pinyinFirst = pinyinCache[menu.label]?.pinyinFirst;
                if(!pinyinFirst) {
                    pinyinFirst = await (await fetch('https://tools.getquicker.cn/api/Chinese/GetFirstPinyin?source='+words)).text();
                    if(pinyinFirst) {
                        pinyinCache[menu.label].pinyinFirst = pinyinFirst;
                        hasNewCache = true;
                    }
                }
                if(pinyinFirst) menu.pinyinFirst = pinyinFirst;
            } catch(e) {
                console.warn(e);
                return;
            }
        }
        if(hasNewCache) {
            putFile('/data/storage/quickopen_pinyin_catche.json', JSON.stringify(pinyinCache));
        }
    }, 0);

    // 添加菜单函数
    function addMenu(name, callback, key, shortcut, value) {
        menus.push({ label: name, value: value||name, key: key || '', shortcut: shortcut, callback: callback });
    }

    function runSiyuanCommand(command, type, event, functions, option, selection) {
        if(type === 'plugin') {
            if (command.callback) {
                command.callback();
            } else if (command.globalCallback) {
                command.globalCallback();
            }
        } else {
            setTimeout(()=>{
                openAny.click('#barCommand').click(`#commands [data-command="${command}"]`);
            }, 0);
        }
    }

    // see https://github.com/siyuan-note/siyuan/blob/1317020c1791edf440da7f836d366567e03dd843/app/src/protyle/util/compatibility.ts#L409
    async function setStorageVal(key, val, cb) {
        if (window.siyuan.config.readonly) {
            return;
        }
        const result = await fetchSyncPost("/api/storage/setLocalStorageVal", {
            app: window.siyuan.ws.app.appId,
            key,
            val,
        });
        if(result && result.code === 0) {
            if (cb) {
                cb();
            }
            return result;
        }
    }
  
    // see https://github.com/siyuan-note/siyuan/blob/e47b8efc2f2611163beca9fad4ee5424001515ff/app/src/protyle/util/compatibility.ts#L258
    async function getStorageVal(key) {
        const result = await fetchSyncPost("/api/storage/getLocalStorage");
        if(result && result.code === 0 && result.data) {
            return result.data[key];
        }
    }

    async function fetchSyncPost(url, data, method = 'POST') {
        return await (await fetch(url, {method: method, body: JSON.stringify(data||{})})).json();
    }

    // 获取文件
    async function getFile(path) {
        return fetch("/api/file/getFile", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                path,
            }),
        }).then((response) => {
            if (response.ok) {
                return response.text();
            } else {
                throw new Error("Failed to get file content");
            }
        }).catch((error) => {
            console.error(error);
        });
    }

    // 存储文件,支持创建文件夹,当isDir true时创建文件夹,忽略文件
     async function putFile(path, content = '', isDir = false) {
        const formData = new FormData();
        formData.append("path", path);
        formData.append("isDir", isDir)
        formData.append("file", new Blob([content]));
        const result = await fetch("/api/file/putFile", {
            method: "POST",
            body: formData,
        });
        const json = await result.json();
        return json;
    }

    function waitFor(conditionFn, timeoutMs=5000) {
      return new Promise((resolve, reject) => {
        const start = Date.now();
        const check = () => {
          if(typeof conditionFn === 'string') 
              conditionFn = () => document.querySelector(conditionFn);
          const result = conditionFn();
          if (result) resolve(result);
          else if (Date.now() - start > timeoutMs) reject();
          else requestAnimationFrame(check); // 利用浏览器刷新周期
        };
        check();
      });
    }

    function isMobile() {
        return !!document.getElementById("sidebar");
    }

    function isBrowser() {
        return !navigator.userAgent.startsWith("SiYuan") ||
            navigator.userAgent.indexOf("iPad") > -1 ||
            (/Android/.test(navigator.userAgent) && !/(?:Mobile)/.test(navigator.userAgent));
    }

    function isMac() {
        return navigator.platform.indexOf("Mac") > -1;
    }

    function updateHotkeyTip(hotkey) {
        if (isMac()) {
            return hotkey;
        }
  
        const KEY_MAP = new Map(Object.entries({
            "⌘": "Ctrl",
            "⌃": "Ctrl",
            "⇧": "Shift",
            "⌥": "Alt",
            "⇥": "Tab",
            "⌫": "Backspace",
            "⌦": "Delete",
            "↩": "Enter",
        }));
  
        const keys = [];
  
        if ((hotkey.indexOf("⌘") > -1 || hotkey.indexOf("⌃") > -1)) keys.push(KEY_MAP.get("⌘"));
        if (hotkey.indexOf("⇧") > -1) keys.push(KEY_MAP.get("⇧"));
        if (hotkey.indexOf("⌥") > -1) keys.push(KEY_MAP.get("⌥"));
  
        // 不能去最后一个,需匹配 F2
        const lastKey = hotkey.replace(/⌘|⇧|⌥|⌃/g, "");
        if (lastKey) {
            keys.push(KEY_MAP.get(lastKey) || lastKey);
        }
  
        return keys.join("+");
    }

    function generateReward(node) {
        const a = document.createElement('a');
        a.href = 'https://ld246.com/article/1745488922117#%E6%89%93%E8%B5%8F%E4%BD%9C%E8%80%85';
        a.textContent = '打赏作者';
        a.target = '_blank';
        a.style.position = 'absolute';
        a.style.right = '0';
        a.style.top = '22px';
        node.appendChild(a);
    }
})();

等待openAny脚本加载完成的方法

1 for循环

// 等待openAny加载完成
for(let i=0;i<5;i++){
    if(typeof openAny !== 'undefined') break;
    const delay = Math.floor(1000/(i+1));
    await new Promise(resolve => setTimeout(resolve, delay));
}
if(typeof openAny === 'undefined') {
    console.error('openAny加载失败');
    return;
}
// 继续下面的操作

2 waitFor

function waitFor(conditionFn, timeoutMs=5000) {
  return new Promise((resolve, reject) => {
    const start = Date.now();
    const check = () => {
      if(typeof conditionFn === 'string') 
          conditionFn = () => document.querySelector(conditionFn);
      const result = conditionFn();
      if (result) resolve(result);
      else if (Date.now() - start > timeoutMs) reject();
      else requestAnimationFrame(check); // 利用浏览器刷新周期
    };
    check();
  });
}
// 等待oopenAny加载完毕后运行
(function run(count=0) {
    setTimeout(()=>{
        if(typeof openAny === 'undefined' && count < 5) return run(count+1);
        if(typeof openAny === 'undefined') {console.error('openAny undefined');return;}
        openAny.addKeymap('', ()=> {
            // your code here
        });
    }, 1000);
})();

image.png

留下你的脚步
推荐阅读