浏览器文本补全脚本
一、功能展示如何在网页里面实现文本补全呢在油猴里面粘贴并保存下面的完整代码然后在网页文本框里面输入索引词就会弹出待选项按下按钮即可自动替换。补全功能如图所示。二、添加地方在下面代码区域添加你想要补全的内容。例打印: console.log();冒号前面为索引词冒号后面为待选项使用中括号就是有多个待选项。const SNIPPETS { 打印: console.log();, 报错: console.error();, log: [ console.log();, console.log(DEBUG:, ...);, console.log(JSON.stringify(obj, null, 2));, console.table(data); ], 循环: [ for (let i 0; i arr.length; i) {\n const item arr[i];\n \n}, arr.forEach((item, index) {\n \n});, for (const key in obj) {\n if (obj.hasOwnProperty(key)) {\n \n }\n} ], 函数: [ function name() {\n \n}, const name () {\n \n};, async function name() {\n try {\n \n } catch (err) {\n console.error(err);\n }\n} ], 判断: if (condition) {\n \n}, 试试: try {\n \n} catch (err) {\n console.error(err);\n}, 框架: !DOCTYPE html\nhtml\nhead\n meta charsetUTF-8\n title文档/title\n/head\nbody\n \n/body\n/html, 请求: axios.get(/api).then(res {\n console.log(res.data);\n}); };三、完整代码// UserScript // name 智能代码补全自动定位 可拖拽 // namespace http://tampermonkey.net/ // version 4.0 // description 下拉菜单自动防遮挡支持鼠标拖拽移动兼容React/Vue // author You // match *://*/* // grant none // /UserScript (function() { use strict; // // ★★★ 配置区域 ★★★ // const SNIPPETS { 打印: console.log();, 报错: console.error();, log: [ console.log();, console.log(DEBUG:, ...);, console.log(JSON.stringify(obj, null, 2));, console.table(data); ], 循环: [ for (let i 0; i arr.length; i) {\n const item arr[i];\n \n}, arr.forEach((item, index) {\n \n});, for (const key in obj) {\n if (obj.hasOwnProperty(key)) {\n \n }\n} ], 函数: [ function name() {\n \n}, const name () {\n \n};, async function name() {\n try {\n \n } catch (err) {\n console.error(err);\n }\n} ], 判断: if (condition) {\n \n}, 试试: try {\n \n} catch (err) {\n console.error(err);\n}, 框架: !DOCTYPE html\nhtml\nhead\n meta charsetUTF-8\n title文档/title\n/head\nbody\n \n/body\n/html, 请求: axios.get(/api).then(res {\n console.log(res.data);\n}); }; // let menuDiv null; let isComposing false; let activeIndex -1; let currentMatches []; let currentWord ; let currentInput null; let currentPage 0; const PAGE_SIZE 9; // ---- 拖拽相关 ---- let isDragging false; let dragOffsetX 0; let dragOffsetY 0; let dragHandle null; // ---- 创建菜单 ---- function createMenu() { if (menuDiv) return; menuDiv document.createElement(div); menuDiv.style.cssText position: fixed; background: #ffffff; border: 1px solid #d1d5db; border-radius: 8px; box-shadow: 0 6px 16px rgba(0,0,0,0.15); max-height: 300px; width: 320px; overflow-y: auto; font-family: Segoe UI, Consolas, monospace; z-index: 999999; display: none; padding: 0 0 4px 0; user-select: none; ; document.body.appendChild(menuDiv); // 创建拖拽手柄顶部灰色条 dragHandle document.createElement(div); dragHandle.style.cssText height: 12px; background: #f3f4f6; cursor: grab; border-radius: 8px 8px 0 0; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #9ca3af; letter-spacing: 4px; border-bottom: 1px solid #e5e7eb; ; dragHandle.textContent ⋮⋮⋮; // 拖拽点阵 dragHandle.addEventListener(mousedown, startDrag); menuDiv.appendChild(dragHandle); } // ---- 拖拽逻辑 ---- function startDrag(e) { e.preventDefault(); e.stopPropagation(); isDragging true; const rect menuDiv.getBoundingClientRect(); dragOffsetX e.clientX - rect.left; dragOffsetY e.clientY - rect.top; menuDiv.style.cursor grabbing; document.addEventListener(mousemove, onDrag); document.addEventListener(mouseup, endDrag); } function onDrag(e) { if (!isDragging) return; e.preventDefault(); let left e.clientX - dragOffsetX; let top e.clientY - dragOffsetY; // 防止拖出屏幕边界 left Math.max(0, Math.min(left, window.innerWidth - menuDiv.offsetWidth)); top Math.max(0, Math.min(top, window.innerHeight - menuDiv.offsetHeight)); menuDiv.style.left left px; menuDiv.style.top top px; menuDiv.style.right auto; menuDiv.style.bottom auto; } function endDrag(e) { isDragging false; menuDiv.style.cursor default; document.removeEventListener(mousemove, onDrag); document.removeEventListener(mouseup, endDrag); } // ---- 智能定位 ---- function positionMenu() { if (!menuDiv || !currentInput) return; const rect currentInput.getBoundingClientRect(); const menuWidth menuDiv.scrollWidth || 320; const menuHeight menuDiv.scrollHeight || 300; // 先计算初始位置默认在输入框下方 let left rect.left; let top rect.bottom 4; // 1. 水平方向修正 if (left menuWidth window.innerWidth) { left window.innerWidth - menuWidth - 10; } if (left 0) left 10; // 2. 垂直方向修正优先在下方下方不够就跳到上方 if (top menuHeight window.innerHeight) { // 检查上方空间是否足够 if (rect.top menuHeight 10) { top rect.top - menuHeight - 4; } else { // 上下都不够就紧贴屏幕底部 top window.innerHeight - menuHeight - 10; } } if (top 0) top 10; menuDiv.style.left left px; menuDiv.style.top top px; menuDiv.style.right auto; menuDiv.style.bottom auto; } // ---- 渲染页面 ---- function renderPage() { if (!menuDiv) return; const start currentPage * PAGE_SIZE; const end start PAGE_SIZE; const pageItems currentMatches.slice(start, end); const totalPages Math.ceil(currentMatches.length / PAGE_SIZE); // 保留拖拽手柄清除其余内容 while (menuDiv.childNodes.length 0) { if (menuDiv.childNodes[0] dragHandle) break; menuDiv.removeChild(menuDiv.childNodes[0]); } // 确保手柄在第一位 if (menuDiv.firstChild ! dragHandle) { menuDiv.insertBefore(dragHandle, menuDiv.firstChild); } // 删除手柄之后的所有内容 while (menuDiv.childNodes.length 1) { menuDiv.removeChild(menuDiv.childNodes[1]); } if (pageItems.length 0 currentPage 0) { currentPage 0; renderPage(); return; } // 1. 渲染代码选项 pageItems.forEach((item, idx) { const num idx 1; const div document.createElement(div); div.style.cssText padding: 6px 12px; cursor: pointer; color: #333; border-bottom: 1px solid #f3f4f6; font-size: 12px; line-height: 1.5; display: flex; align-items: flex-start; white-space: pre-wrap; word-break: break-all; user-select: none; ; const numSpan document.createElement(span); numSpan.style.cssText display: inline-block; width: 24px; color: #2563eb; font-weight: bold; margin-right: 8px; flex-shrink: 0; ; numSpan.textContent num; const codeSpan document.createElement(span); codeSpan.textContent item.snippet; div.appendChild(numSpan); div.appendChild(codeSpan); div.addEventListener(mousedown, (e) { e.preventDefault(); e.stopPropagation(); }); div.addEventListener(click, (e) { e.stopPropagation(); const globalIdx currentPage * PAGE_SIZE idx; applySnippet(globalIdx); hideMenu(); }); div.addEventListener(mouseenter, () { activeIndex idx; highlightItem(activeIndex); }); menuDiv.appendChild(div); }); // 2. 底部翻页栏 if (totalPages 1) { const footer document.createElement(div); footer.style.cssText display: flex; justify-content: space-between; align-items: center; padding: 6px 12px; border-top: 1px solid #e5e7eb; background: #f9fafb; font-size: 12px; color: #6b7280; position: sticky; bottom: 0; user-select: none; ; const prev document.createElement(span); prev.textContent ‹ 上一页; prev.style.cssText cursor: pointer; padding: 2px 6px; border-radius: 4px;; prev.addEventListener(click, (e) { e.stopPropagation(); if (currentPage 0) { currentPage--; renderPage(); } }); if (currentPage 0) prev.style.opacity 0.5; const info document.createElement(span); info.textContent ${currentPage 1} / ${totalPages}; const next document.createElement(span); next.textContent 下一页 ›; next.style.cssText cursor: pointer; padding: 2px 6px; border-radius: 4px;; next.addEventListener(click, (e) { e.stopPropagation(); if (currentPage totalPages - 1) { currentPage; renderPage(); } }); if (currentPage totalPages - 1) next.style.opacity 0.5; footer.appendChild(prev); footer.appendChild(info); footer.appendChild(next); menuDiv.appendChild(footer); } // 先显示再定位防止获取高度为0 menuDiv.style.display block; // 使用 requestAnimationFrame 确保DOM渲染完成后再计算位置 requestAnimationFrame(() { positionMenu(); }); activeIndex -1; } function highlightItem(index) { // 跳过第一个手柄只高亮代码项 const items menuDiv.querySelectorAll(div:not(:first-child):not(:last-child)); items.forEach((el, i) { el.style.background i index ? #e3f2fd : transparent; }); } function showMenu(inputEl, word, matches) { if (!menuDiv) createMenu(); currentInput inputEl; currentWord word; currentMatches matches; currentPage 0; if (!matches || matches.length 0) { hideMenu(); return; } renderPage(); } function hideMenu() { if (menuDiv) menuDiv.style.display none; currentMatches []; activeIndex -1; currentPage 0; // 如果拖拽状态未结束强制清除 if (isDragging) endDrag(); } // ---- 核心插入逻辑保留 ---- function applySnippet(globalIdx) { if (!currentInput || !currentWord) return; if (globalIdx 0 || globalIdx currentMatches.length) return; const replacement currentMatches[globalIdx].snippet; if (!replacement) return; const isTextarea currentInput.tagName TEXTAREA || currentInput.tagName INPUT; const isEditable currentInput.isContentEditable; if (isTextarea) { const start currentInput.selectionStart; const text currentInput.value; const before text.substring(0, start); const regex /([a-zA-Z0-9_\u4e00-\u9fa5])$/; const match before.match(regex); if (match match[1] currentWord) { const newText text.substring(0, start - currentWord.length) replacement text.substring(start); const newPos start - currentWord.length replacement.length; let valueSetter null; let proto Object.getPrototypeOf(currentInput); while (proto !valueSetter) { const desc Object.getOwnPropertyDescriptor(proto, value); if (desc desc.set) valueSetter desc.set; proto Object.getPrototypeOf(proto); } if (valueSetter) { valueSetter.call(currentInput, newText); } else { currentInput.value newText; } currentInput.selectionStart currentInput.selectionEnd newPos; currentInput.dispatchEvent(new Event(input, { bubbles: true })); currentInput.dispatchEvent(new Event(change, { bubbles: true })); setTimeout(() { if (!currentInput) return; if (currentInput.value ! newText) { if (valueSetter) { valueSetter.call(currentInput, newText); } else { currentInput.value newText; } currentInput.selectionStart currentInput.selectionEnd newPos; currentInput.dispatchEvent(new Event(input, { bubbles: true })); } }, 0); } } else if (isEditable) { const sel window.getSelection(); if (!sel.rangeCount) return; const range sel.getRangeAt(0); const node range.startContainer; if (node.nodeType Node.TEXT_NODE) { const text node.textContent; const offset range.startOffset; const before text.substring(0, offset); const regex /([a-zA-Z0-9_\u4e00-\u9fa5])$/; const match before.match(regex); if (match match[1] currentWord) { range.setStart(node, offset - currentWord.length); range.setEnd(node, offset); sel.removeAllRanges(); sel.addRange(range); document.execCommand(insertText, false, replacement); } } } } // ---- 事件监听保持原有逻辑 ---- document.addEventListener(input, function(e) { if (isComposing) return; const el document.activeElement; if (!el) return; const isInput el.tagName TEXTAREA || el.tagName INPUT || el.isContentEditable; if (!isInput) return; let text, start; if (el.tagName TEXTAREA || el.tagName INPUT) { text el.value; start el.selectionStart; } else { const sel window.getSelection(); if (!sel.rangeCount) return; const range sel.getRangeAt(0); const node range.startContainer; if (node.nodeType ! Node.TEXT_NODE) return; text node.textContent; start range.startOffset; } const before text.substring(0, start); const regex /([a-zA-Z0-9_\u4e00-\u9fa5])$/; const match before.match(regex); if (match) { const word match[1]; if (word.length 1) { hideMenu(); return; } const expanded []; Object.keys(SNIPPETS).forEach(key { if (key.includes(word)) { const val SNIPPETS[key]; if (Array.isArray(val)) { val.forEach(snippet expanded.push({ key, snippet })); } else { expanded.push({ key, snippet: val }); } } }); if (expanded.length 0) { showMenu(el, word, expanded); } else { hideMenu(); } } else { hideMenu(); } }); document.addEventListener(keydown, function(e) { if (!menuDiv || menuDiv.style.display none) return; if (!isComposing e.key 1 e.key 9) { e.preventDefault(); const num parseInt(e.key) - 1; const globalIdx currentPage * PAGE_SIZE num; if (globalIdx currentMatches.length) { applySnippet(globalIdx); hideMenu(); } return; } if (e.key PageDown || e.key ArrowRight) { e.preventDefault(); const total Math.ceil(currentMatches.length / PAGE_SIZE); if (currentPage total - 1) { currentPage; renderPage(); } return; } if (e.key PageUp || e.key ArrowLeft) { e.preventDefault(); if (currentPage 0) { currentPage--; renderPage(); } return; } if (e.key ArrowDown) { e.preventDefault(); const pageItems currentMatches.slice(currentPage * PAGE_SIZE, (currentPage 1) * PAGE_SIZE); if (pageItems.length 0) return; activeIndex (activeIndex 1) % pageItems.length; highlightItem(activeIndex); } else if (e.key ArrowUp) { e.preventDefault(); const pageItems currentMatches.slice(currentPage * PAGE_SIZE, (currentPage 1) * PAGE_SIZE); if (pageItems.length 0) return; activeIndex (activeIndex - 1 pageItems.length) % pageItems.length; highlightItem(activeIndex); } else if (e.key Enter) { e.preventDefault(); if (activeIndex 0) { const pageItems currentMatches.slice(currentPage * PAGE_SIZE, (currentPage 1) * PAGE_SIZE); if (activeIndex pageItems.length) { const globalIdx currentPage * PAGE_SIZE activeIndex; applySnippet(globalIdx); hideMenu(); } } } else if (e.key Escape) { hideMenu(); } }); document.addEventListener(mousedown, function(e) { if (menuDiv !menuDiv.contains(e.target)) { hideMenu(); } }); document.addEventListener(compositionstart, function() { isComposing true; }); document.addEventListener(compositionend, function() { isComposing false; const el document.activeElement; if (el) el.dispatchEvent(new Event(input, { bubbles: true })); }); })();

相关新闻

零基础具身智能机械臂实战项目开发全套视频课程百度云网盘下载

零基础具身智能机械臂实战项目开发全套视频课程百度云网盘下载

在具身智能的宏大叙事中,机械臂不再仅仅是执行预设轨迹的自动化设备,而是进化为具备感知、决策与交互能力的智能体。要实现这一跨越,核心在于打破单一传感器的局限,将视觉、触觉、力觉等多模态数据在底层进行深度融合。这种融合并…

2026/8/17 9:24:39 阅读更多 →
论文写到崩溃?你可能缺的不是才华,是一个“学术脚手架”

论文写到崩溃?你可能缺的不是才华,是一个“学术脚手架”

各位同学、各位写论文写到头秃的朋友们,大家好。 我是你们的老朋友,专门聊论文写作那点事儿的博主。今天咱们不聊虚的,不说正确的废话,来解决一个非常具体、非常痛的问题:当你的论文写作陷入泥潭,感觉脑子…

2026/8/17 8:15:26 阅读更多 →
帧规则计时器:Lua游戏开发中稳定管理技能冷却与敌人刷新的方案

帧规则计时器:Lua游戏开发中稳定管理技能冷却与敌人刷新的方案

这次我们来看一个在简单游戏开发中实现计时器的技术方案,核心是理解并应用“帧规则”。对于使用 Lua 或类似 PICO-8 这类轻量级游戏引擎的开发者来说,如何精确、稳定地管理游戏中的各种计时逻辑,比如技能冷却、敌人刷新、动画播放&#xff0c…

2026/8/17 11:46:47 阅读更多 →

最新新闻

AI代理权限管理新范式:意图主导的工具授权设计与LangChain实战

AI代理权限管理新范式:意图主导的工具授权设计与LangChain实战

1. 从“意图”出发:为什么AI代理的权限管理需要新范式? 最近在设计和实现一些复杂的AI代理系统时,我反复遇到一个棘手的问题:如何安全、灵活地授权AI代理使用外部工具?传统的做法,比如给代理一个固定的工具…

2026/8/17 12:27:05 阅读更多 →
原生HTML中渐进式引入Vue:从CDN到核心功能实战指南

原生HTML中渐进式引入Vue:从CDN到核心功能实战指南

1. 项目概述:为什么要在原生HTML里用Vue? 很多刚接触前端的朋友,尤其是从传统网页开发(HTMLCSSJS)转过来的,一听到Vue、React这些框架,第一反应就是“好复杂,要配环境、要脚手架、要…

2026/8/17 12:27:05 阅读更多 →
交通工程AI智能体构建:从LoRA微调到工具调用的全流程实践

交通工程AI智能体构建:从LoRA微调到工具调用的全流程实践

1. 项目概述:为什么交通工程需要专属的生成式AI智能体?如果你在交通工程领域工作过,无论是做交通流分析、信号配时优化,还是处理复杂的路网规划,你肯定经历过这样的场景:面对海量的交通检测器数据、CAD图纸…

2026/8/17 12:27:05 阅读更多 →
智能路由架构:从单一模型到专家模型池的编码任务优化实践

智能路由架构:从单一模型到专家模型池的编码任务优化实践

1. 从“单一模型”到“智能路由”:编码任务的新范式 在过去的几年里,我们见证了大型语言模型在代码生成、补全和调试方面的能力突飞猛进。无论是GitHub Copilot、Cursor,还是各类开源的代码模型,它们都极大地提升了开发者的效率。…

2026/8/17 12:27:05 阅读更多 →
大语言模型智能体过早承诺问题:诊断、根因与系统性优化策略

大语言模型智能体过早承诺问题:诊断、根因与系统性优化策略

1. 项目概述:当智能体过早“拍板”时最近在设计和调试基于大语言模型的智能体时,我反复遇到一个令人头疼的问题:智能体在执行任务时,经常在信息不充分或思考不完整的情况下,就急匆匆地做出了最终决策或行动。比如&…

2026/8/17 12:27:04 阅读更多 →
基于图计算的LLM智能体框架:MyAG如何实现可组合与可分析

基于图计算的LLM智能体框架:MyAG如何实现可组合与可分析

1. 项目概述:为什么我们需要一个“可组合”的智能体框架?最近在折腾大语言模型应用落地的朋友,估计都绕不开“智能体”这个概念。从AutoGPT的爆火,到各种“AI员工”、“数字同事”的涌现,大家似乎都看到了让LLM自主完成…

2026/8/17 12:26:03 阅读更多 →

日新闻

LabVIEW异步调用实战:从原理到生产者消费者模式,解决界面卡顿与并行处理难题

LabVIEW异步调用实战:从原理到生产者消费者模式,解决界面卡顿与并行处理难题

1. 项目概述:为什么异步调用是LabVIEW进阶的必修课? 如果你用LabVIEW做过稍微复杂点的项目,尤其是涉及界面响应、多任务并行或者硬件IO等待的场景,大概率遇到过这样的窘境:前面板点个按钮,整个程序就“卡死…

2026/8/17 0:00:08 阅读更多 →
LabVIEW异步调用实战:解决界面卡顿与并行处理难题

LabVIEW异步调用实战:解决界面卡顿与并行处理难题

1. 项目概述:为什么异步调用是LabVIEW进阶的必经之路如果你在LabVIEW里写过稍微复杂点的程序,尤其是涉及到界面响应、多任务并行或者硬件IO等待,大概率会遇到一个头疼的问题:程序“卡”住了。前面板点不动,进度条不更新…

2026/8/17 0:00:08 阅读更多 →
飞书局域网文件传输实战:3种方案实现高速点对点传输

飞书局域网文件传输实战:3种方案实现高速点对点传输

1. 项目概述:为什么要在局域网内用飞书传文件? 飞书作为一款主流的协同办公套件,其核心功能是围绕云端协作设计的。无论是文档、表格还是文件,通常的分享逻辑都是“上传到云端 -> 生成链接 -> 分享给同事”。这个流程在互联…

2026/8/17 0:00:08 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/17 2:58:27 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/17 2:58:30 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/17 2:58:32 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/16 6:00:23 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/16 6:00:24 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/16 6:00:27 阅读更多 →