commit 760f3ec0d0fc16aef683d5341fad24b9a6c8ff0e Author: ytc1012 <18001193130@163.com> Date: Wed Dec 10 18:18:30 2025 +0800 first commit diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..1e2b006 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(wc:*)" + ] + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e928755 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,227 @@ +# BlurText 更新日志 + +## v2.0.0 (2025-01-10) - 文本选择模式 + +### 🎉 新功能 + +#### **双模式支持** +现在 BlurText 支持两种模糊模式,满足不同场景需求: + +1. **🖱️ 元素模式**(原有功能) + - 鼠标悬停查看高亮 + - 点击元素进行模糊 + - 适用于结构化内容(表格、卡片等) + +2. **📝 文本选择模式**(新增功能)⭐ + - 拖动鼠标选择任意文本 + - 点击浮动按钮模糊选中内容 + - **完美解决纯文本节点的模糊问题** + - 适用于文章、段落等纯文本内容 + +--- + +### 🔧 技术实现 + +#### **文本选择模式核心特性** + +使用标准 Selection API 实现: +```javascript +// 1. 监听文本选择 +document.addEventListener('mouseup', handleTextSelection); + +// 2. 获取选中文本 +const selection = window.getSelection(); +const range = selection.getRangeAt(0); + +// 3. 包裹并模糊 +const span = document.createElement('span'); +range.surroundContents(span); +span.classList.add('blurtext-blurred'); +``` + +#### **智能浮动按钮** +- 自动定位在选中文本下方 +- 渐入动画效果 +- 点击后自动隐藏 + +#### **错误处理** +- 捕获复杂 HTML 结构的异常 +- 提供友好的错误提示 +- 不会破坏页面功能 + +--- + +### 🎨 UI 改进 + +#### **Popup 界面升级** +- 新增模式切换按钮(图形化设计) +- 动态使用提示(根据模式显示不同说明) +- 更清晰的视觉反馈 + +#### **模式图标** +- 🖱️ 元素模式 - 代表点击操作 +- 📝 文本选择模式 - 代表文本选择 + +#### **CSS 样式增强** +- 新增模糊按钮样式(渐变背景 + 阴影) +- 按钮动画效果(弹出 + 悬停缩放) +- 更好的视觉层级 + +--- + +### 📝 使用指南 + +#### **元素模式使用方法** +``` +1. 点击扩展图标打开 Popup +2. 选择"元素模式" +3. 点击"开启模糊模式" +4. 鼠标悬停查看高亮 +5. 点击元素进行模糊 +``` + +#### **文本选择模式使用方法** ⭐ +``` +1. 点击扩展图标打开 Popup +2. 选择"文本选择模式" +3. 点击"开启模糊模式" +4. 拖动鼠标选择文本 +5. 点击浮动按钮"🔒 模糊选中文本" +6. 可以多次选择和模糊 +``` + +--- + +### 🆚 两种模式对比 + +| 特性 | 元素模式 | 文本选择模式 | +|------|---------|-------------| +| **操作方式** | 点击元素 | 拖动选择文本 | +| **适用场景** | 结构化内容 | 纯文本内容 | +| **精确度** | 按元素边界 | 按字符级别 | +| **DOM 修改** | 不修改 | 添加 span 包裹 | +| **预览方式** | 悬停高亮 | 浏览器原生选择 | +| **典型使用** | 表格、卡片、按钮 | 段落、文章、评论 | + +--- + +### 🎯 使用场景示例 + +#### **场景 1:文章中的敏感信息** +```html +

用户张三的手机号是138-8888-9999,邮箱是zhang@example.com

+``` + +**元素模式**: +- 点击 → 模糊整个段落 ❌ + +**文本选择模式**: +- 选择"138-8888-9999" → 只模糊手机号 ✅ +- 选择"zhang@example.com" → 只模糊邮箱 ✅ + +#### **场景 2:表格数据** +```html + + + +
姓名李四
工号E12345
+``` + +**元素模式**: +- 点击第二列的 td → 精确模糊单元格 ✅ + +**文本选择模式**: +- 也可以选择文本模糊,但元素模式更快捷 + +--- + +### 📊 代码变更统计 + +| 文件 | 变更类型 | 行数变化 | +|------|---------|---------| +| content.js | 新增功能 | +100 行 | +| popup.html | UI 更新 | +30 行 | +| popup.js | 逻辑扩展 | +60 行 | +| content.css | 样式新增 | +43 行 | +| **总计** | | **+233 行** | + +--- + +### 🐛 已修复问题 + +1. ✅ **popup 关闭问题** + - 说明:这是浏览器扩展的默认行为,不是 bug + - 正常使用:开启模糊模式后,popup 会自动关闭 + +2. ✅ **纯文本节点无法模糊** + - 通过文本选择模式完美解决 + - 不再需要复杂的文本节点检测 + +--- + +### 🔍 技术亮点 + +#### **1. Selection API 的正确使用** +- 使用 `window.getSelection()` 获取选区 +- 使用 `range.surroundContents()` 包裹文本 +- 正确处理 `surroundContents` 异常 + +#### **2. 模式切换机制** +- 动态添加/移除事件监听器 +- 根据模式显示不同的 UI 提示 +- 实时切换无需刷新 + +#### **3. 用户体验优化** +- 浮动按钮自动定位 +- 平滑动画过渡 +- 友好的错误提示 + +--- + +### 🚀 性能优化 + +- 事件监听器按需添加/移除 +- 避免不必要的 DOM 查询 +- CSS 动画使用 GPU 加速(transform) + +--- + +### 📚 参考资料 + +本次更新参考了以下浏览器扩展的实现: +- [blurweb.app](https://www.blurweb.app/) - 文本选择模式设计 +- [Selection API](https://developer.mozilla.org/en-US/docs/Web/API/Selection) - Mozilla 文档 + +--- + +### 🔮 后续计划 + +1. **区域框选模式** - 拖拽绘制矩形模糊区域 +2. **模糊记忆** - 页面刷新后保持模糊状态 +3. **快捷键支持** - Ctrl+B 快速切换模式 +4. **批量操作** - 一次选择多个区域 + +--- + +## v1.0.0 (2025-01-09) - 初始版本 + +### 功能 +- ✅ 元素点击模糊 +- ✅ 模糊强度调节 +- ✅ 批量清除模糊 +- ✅ ESC 键退出 + +--- + +## 升级建议 + +### 从 v1.0.0 升级到 v2.0.0 + +1. 刷新扩展(chrome://extensions/) +2. 重新加载需要使用的网页 +3. 尝试新的文本选择模式 + +**兼容性**: +- ✅ 完全向后兼容 +- ✅ 元素模式保持不变 +- ✅ 无需修改使用习惯 diff --git a/FIXES.md b/FIXES.md new file mode 100644 index 0000000..59ea1a2 --- /dev/null +++ b/FIXES.md @@ -0,0 +1,204 @@ +# BlurText 修复说明 + +## 🔄 重大变更(2025-01-10) + +### 移除文本节点模糊功能 + +**决策原因**: +文本节点自动检测和包裹功能虽然看起来智能,但引入了过多复杂性和bug: +1. 预览高亮和实际模糊的交互逻辑复杂 +2. DOM 操作频繁,容易出现元素消失的问题 +3. 预览 span 的生命周期管理困难 +4. 用户体验不够稳定 + +**回归简单模式**: +- ✅ 只模糊 HTML 元素(span, div, p, td 等) +- ✅ 鼠标悬停高亮,点击即模糊 +- ✅ 稳定可靠,不会出现元素消失的问题 +- ❌ 不再自动检测和包裹纯文本节点 +- ❌ 不再智能识别敏感信息(手机号、邮箱等) + +**使用建议**: +- 如果需要模糊纯文本,可以先手动用 `` 包裹 +- 或者点击包含该文本的父元素进行整体模糊 + +--- + +## 🐛 已修复的问题 + +### 问题 1:Popup 卡片在点击页面后消失 + +**症状**: +- 开启模糊模式后,点击扩展图标打开 popup +- 点击网页上的文字进行模糊 +- Popup 卡片立即消失 + +**原因**: +这是浏览器扩展的**默认行为**,不是 bug: +- 当用户点击 popup 外部的任何区域(包括网页内容)时,浏览器会自动关闭 popup +- 这是 Chrome/Edge 扩展的标准行为,无法通过配置改变 + +**解决方案**: +1. **正常使用流程**: + - 点击扩展图标 → 开启模糊模式 → Popup 自动关闭 + - 直接在网页上点击元素进行模糊 + - 需要调整强度或关闭模式时,再次点击扩展图标打开 popup + +2. **替代方案**(未来考虑): + - 添加侧边栏模式(使用 `chrome.sidePanel` API,需要 Manifest V3 + Chrome 114+) + - 添加快捷键支持(无需打开 popup 即可切换模式) + +--- + +## ✅ 当前功能 + +### 基础模糊功能 +```html +
+ 用户名 + 张三 +
+``` + +**使用方法**: +1. 开启模糊模式 +2. 鼠标悬停在元素上 → 显示蓝色高亮边框 +3. 点击元素 → 应用模糊效果 +4. 再次点击 → 取消模糊 + +**特点**: +- ✅ 悬停高亮的元素 = 点击后模糊的元素(所见即所得) +- ✅ 可以模糊任何 HTML 元素 +- ✅ 可调节模糊强度(5-20px) +- ✅ 支持批量清除所有模糊 +- ✅ ESC 键退出模糊模式 + +--- + +## 🎯 适用场景 + +### 场景 1:结构化数据 +```html + + + + + +
姓名张三
+``` +- 鼠标悬停第二个 `` → 高亮 +- 点击 → 模糊 ✅ + +### 场景 2:带标签的元素 +```html +

+ 手机号: + 138-8888-9999 +

+``` +- 鼠标悬停 `` → 高亮手机号 +- 点击 → 模糊手机号 ✅ + +### 场景 3:纯文本(需要手动处理) +```html +

用户 张三 的手机号是 138-8888-9999

+``` +- 悬停任意位置 → 高亮整个 `

` +- 点击 → 模糊整段文字 +- **如需只模糊"张三"**:先手动编辑 HTML,用 `张三` 包裹 + +--- + +## 🔧 技术实现 + +### 简化后的核心逻辑 + +**content.js 核心函数**: + +```javascript +// 1. 处理点击 - 简单直接 +function handleClick(e) { + if (!isBlurMode) return; + e.preventDefault(); + e.stopPropagation(); + + let target = e.target; + if (target.classList.contains('blurtext-hint')) return; + + // 直接切换目标元素的模糊状态 + toggleBlur(target); +} + +// 2. 处理悬停 - 高亮预览 +function handleMouseOver(e) { + if (!isBlurMode) return; + + const target = e.target; + if (target.classList.contains('blurtext-hint') || + target.classList.contains('blurtext-blurred')) { + return; + } + + removeAllHighlights(); + target.classList.add('blurtext-highlight'); +} + +// 3. 移除高亮 - 简单清理 +function removeAllHighlights() { + const highlighted = document.querySelectorAll('.blurtext-highlight'); + highlighted.forEach(el => { + el.classList.remove('blurtext-highlight'); + }); +} +``` + +**代码行数对比**: +- 之前:531 行(包含文本节点检测、智能识别、预览管理) +- 现在:约 250 行(移除了约 280 行复杂逻辑) +- 减少 53% 代码量,提升稳定性 + +--- + +## 🧪 测试步骤 + +1. 刷新扩展(`chrome://extensions/`) +2. 打开任意网页 +3. 点击扩展图标,开启模糊模式 +4. **测试基础模糊**: + - 鼠标悬停在任意元素上 → 看到蓝色边框 + - 点击元素 → 成功模糊 ✅ + - 再次点击 → 取消模糊 ✅ +5. **测试强度调整**: + - 打开 popup,拖动滑块 + - 已模糊的元素实时更新强度 ✅ +6. **测试批量清除**: + - 点击"清除所有模糊"按钮 + - 所有模糊效果移除 ✅ + +--- + +## 📝 后续计划 + +基于简单稳定的架构,未来可以考虑: + +1. **框选模糊**:拖拽鼠标框选区域进行模糊 +2. **模糊记忆**:页面刷新后保持模糊状态 +3. **快捷键**:Ctrl+B 快速切换模糊模式 +4. **预设模板**:保存常用的模糊配置 +5. **图片模糊**:支持模糊图片元素 + +--- + +## 💡 开发经验总结 + +**设计原则**: +1. **简单优于复杂**:不要过度设计,用户需要的是稳定可靠的功能 +2. **所见即所得**:悬停预览必须和点击结果完全一致 +3. **DOM 操作要谨慎**:频繁的 DOM 修改容易引入 bug +4. **渐进增强**:先做好基础功能,再逐步添加高级特性 + +**避免的陷阱**: +- ❌ 自动检测和包裹文本节点(DOM 操作复杂,容易出问题) +- ❌ 临时元素管理(生命周期难以控制) +- ❌ 智能识别(正则匹配不够可靠) +- ✅ 让用户明确点击目标元素(简单直接) diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..663a70d --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,186 @@ +# 安装和调试指南 + +## 🚀 快速开始 + +### 第一步:生成图标 + +1. 在浏览器中打开 `icon-generator.html` 文件 +2. 右键点击每个图标,选择"另存为图像" +3. 将图标保存到 `icons/` 文件夹,文件名分别为: + - `icon16.png` + - `icon32.png` + - `icon48.png` + - `icon128.png` + +> 💡 **提示**: 如果右键保存不方便,可以点击每个图标下方的"下载"按钮 + +### 第二步:安装扩展 + +1. 打开 Chrome 浏览器 +2. 在地址栏输入 `chrome://extensions/` 并回车 +3. 开启右上角的"**开发者模式**"开关 +4. 点击"**加载已解压的扩展程序**" +5. 选择 `blurweb` 文件夹 +6. 看到扩展出现在列表中,说明安装成功! + +### 第三步:测试功能 + +#### 方法一:使用测试页面 + +1. 在浏览器中打开 `test.html` 文件 +2. 按照页面上的说明进行测试 + +#### 方法二:测试任意网页 + +1. 打开任意网页(如百度、GitHub 等) +2. 点击浏览器工具栏的 BlurText 图标(紫色图标) +3. 点击"开启模糊模式"按钮 +4. 在网页上点击任意文字,观察模糊效果 + +## 🔍 故障排查 + +### 问题 1:点击文字没有反应 + +**可能原因和解决方法:** + +#### 1. 扩展未正确加载 +- 检查:访问 `chrome://extensions/`,确认 BlurText 已启用 +- 解决:如果未启用,点击开关启用;如果有错误提示,重新加载扩展 + +#### 2. Content Script 未注入 +- 检查:按 F12 打开开发者工具,查看 Console 标签页 +- 应该看到:`[BlurText] Content script loaded` +- 如果没有,刷新页面(F5)后重试 + +#### 3. 消息未发送成功 +- 检查:右键点击扩展图标 → 检查弹出窗口 → 查看 Console +- 应该看到:`[BlurText] Toggle button clicked` 和 `[BlurText] Message sent successfully` +- 如果看到错误,尝试重新加载扩展 + +#### 4. 页面刷新问题 +- 解决:在安装扩展后,刷新所有打开的网页 +- 或者重新打开新标签页测试 + +### 问题 2:提示"请刷新页面后重试" + +**原因:** Content Script 尚未注入到页面 + +**解决:** +1. 刷新当前页面(F5) +2. 再次点击扩展图标 +3. 点击"开启模糊模式" + +### 问题 3:扩展图标不显示 + +**原因:** 图标文件未正确生成或路径错误 + +**解决:** +1. 确认 `icons/` 文件夹存在 +2. 确认包含所有 4 个图标文件 +3. 文件名必须完全匹配:`icon16.png`, `icon32.png`, `icon48.png`, `icon128.png` +4. 重新加载扩展 + +### 问题 4:某些网页无法使用 + +**原因:** 浏览器限制扩展在特殊页面运行 + +**说明:** 以下页面不支持扩展: +- `chrome://` 开头的页面(如设置页、扩展页) +- `chrome-extension://` 开头的页面 +- Chrome Web Store 页面 +- 新标签页(某些情况下) + +**解决:** 在普通网页上使用(如百度、GitHub、新闻网站等) + +## 🐛 调试技巧 + +### 查看 Content Script 日志 + +1. 在网页上按 F12 打开开发者工具 +2. 切换到 Console 标签 +3. 筛选显示 `[BlurText]` 日志 +4. 开启模糊模式后,应该看到: + ``` + [BlurText] Content script loaded + [BlurText] Received message: {action: "toggleBlurMode", ...} + [BlurText] Toggle blur mode: true intensity: 10 + [BlurText] Enabling blur mode + [BlurText] Event listeners attached + ``` + +### 查看 Popup 日志 + +1. 右键点击扩展图标 +2. 选择"检查弹出窗口" +3. 在打开的开发者工具中查看 Console +4. 点击按钮时应该看到对应的日志 + +### 测试点击事件 + +1. 开启模糊模式 +2. 点击网页任意元素 +3. Console 中应该显示: + ``` + [BlurText] Click detected, isBlurMode: true + [BlurText] Target element: DIV some-class + [BlurText] Adding blur to element, intensity: 10 + [BlurText] Total blurred elements: 1 + ``` + +### 检查 CSS 是否生效 + +1. 开启模糊模式后点击一个元素 +2. 右键该元素 → 检查 +3. 在 Elements 标签中,应该看到元素有 `blurtext-blurred` 类 +4. 在 Styles 中应该看到: + ```css + .blurtext-blurred { + filter: blur(10px); + ... + } + ``` + +## ✅ 确认安装成功的标志 + +1. ✅ `chrome://extensions/` 中看到 BlurText 扩展 +2. ✅ 扩展已启用(开关是蓝色的) +3. ✅ 工具栏显示紫色扩展图标 +4. ✅ 点击图标弹出精美的控制面板 +5. ✅ 打开 `test.html` 能看到测试页面 +6. ✅ 开启模糊模式后,页面顶部显示紫色提示条 +7. ✅ 鼠标悬停在文字上有蓝色虚线边框 +8. ✅ 点击文字后变模糊 + +## 📞 获取帮助 + +如果以上方法都无法解决问题: + +1. **检查浏览器版本**:确保使用最新版 Chrome/Edge +2. **尝试其他网页**:在多个网站测试 +3. **查看完整日志**:保存 Console 中的所有日志信息 +4. **重新安装**: + - 移除扩展 + - 关闭浏览器 + - 重新打开浏览器 + - 重新加载扩展 + +## 🎯 预期效果演示 + +### 正常工作流程 + +1. 点击扩展图标 → 弹出控制面板 ✅ +2. 点击"开启模糊模式" → 页面顶部显示提示 ✅ +3. 鼠标移到文字上 → 蓝色虚线边框 ✅ +4. 点击文字 → 变模糊 ✅ +5. 再次点击 → 取消模糊 ✅ +6. 按 ESC → 退出模糊模式 ✅ + +### 视觉效果 + +- **模糊前**: 文字清晰可读 +- **模糊后**: 文字变得模糊,像毛玻璃效果 +- **模糊强度**: 可通过滑块调节,范围 5px-20px + +--- + +**如果一切正常,恭喜你成功安装了 BlurText!🎉** diff --git a/README.md b/README.md new file mode 100644 index 0000000..b45033f --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +# BlurText - 文字模糊保护插件 + +一款简单实用的浏览器扩展,专为屏幕分享和录制场景设计,帮助你快速模糊敏感文字信息,保护隐私安全。 + +## ✨ 功能特点 + +- 🖱️ **一键模糊**:点击即可模糊任意网页文字 +- 🎚️ **可调强度**:5-20px 模糊强度自由调节 +- 🔄 **即点即消**:再次点击取消模糊效果 +- 🗑️ **批量清除**:一键清除所有模糊效果 +- ⚡ **实时生效**:无需刷新,立即看到效果 +- 🔒 **本地处理**:所有数据本地存储,不上传云端 + +## 📦 安装方法 + +### Chrome / Edge / 其他 Chromium 浏览器 + +1. 下载本项目或克隆到本地 +2. 打开浏览器,进入扩展程序管理页面: + - Chrome: `chrome://extensions/` + - Edge: `edge://extensions/` +3. 开启右上角的"开发者模式" +4. 点击"加载已解压的扩展程序" +5. 选择本项目的文件夹 +6. 安装完成! + +## 🎯 使用方法 + +### 基础使用 + +1. 点击浏览器工具栏的 BlurText 图标 +2. 点击"开启模糊模式"按钮 +3. 在网页上点击要模糊的文字元素 +4. 再次点击已模糊的元素可取消模糊 +5. 按 `ESC` 键退出模糊模式 + +### 调整模糊强度 + +- 在弹出窗口中拖动"模糊强度"滑块 +- 范围:5px(轻微模糊)到 20px(强烈模糊) +- 实时生效,无需重新操作 + +### 清除所有模糊 + +- 点击弹出窗口中的"清除所有模糊"按钮 +- 所有模糊效果将立即移除 + +## 💡 使用场景 + +- **技术分享**:录制教程时隐藏 API Key、Token 等敏感信息 +- **在线会议**:演示时保护客户信息、内部数据 +- **直播带货**:展示后台时模糊订单、联系方式 +- **客服工作**:屏幕共享时保护用户隐私 +- **内容创作**:录制视频时快速处理敏感内容 + +## 🔧 技术栈 + +- **Manifest V3**:使用最新的浏览器扩展标准 +- **原生 JavaScript**:无框架依赖,轻量高效 +- **CSS Filter**:使用 CSS `filter: blur()` 实现模糊效果 +- **Chrome Storage API**:本地存储用户配置 + +## 📂 项目结构 + +``` +blurweb/ +├── manifest.json # 扩展配置文件 +├── popup.html # 弹出窗口界面 +├── popup.js # 弹出窗口逻辑 +├── content.js # 内容脚本(核心功能) +├── content.css # 注入样式 +├── icons/ # 图标文件夹 +│ ├── icon16.png +│ ├── icon32.png +│ ├── icon48.png +│ └── icon128.png +└── README.md # 说明文档 +``` + +## 🚀 后续计划 + +- [ ] 图片模糊功能 +- [ ] 区域模糊(矩形选择) +- [ ] 自动识别敏感信息(手机号、身份证等) +- [ ] 模糊记忆功能(页面刷新后保持) +- [ ] 导出/导入配置 +- [ ] 快捷键支持 +- [ ] Firefox 版本 + +## 🤝 贡献 + +欢迎提交 Issue 和 Pull Request! + +## 📄 许可证 + +MIT License + +## ⚠️ 注意事项 + +1. 模糊效果仅在当前页面生效,刷新后需要重新操作 +2. 某些动态加载的内容可能需要重新模糊 +3. 模糊效果只是视觉隐藏,不影响网页的实际数据 +4. 建议在正式录制前测试模糊效果 + +## 📞 反馈 + +如有问题或建议,欢迎提交 Issue。 + +--- + +**开发初衷**:为了让屏幕分享和录制更安全、更便捷,不再需要后期打码,节省时间,保护隐私。 diff --git a/content.css b/content.css new file mode 100644 index 0000000..bbc7bbe --- /dev/null +++ b/content.css @@ -0,0 +1,113 @@ +/* content.css - 注入到网页的样式 */ + +/* 模糊效果类 */ +.blurtext-blurred { + filter: blur(var(--blur-intensity, 10px)) !important; + user-select: none !important; + pointer-events: auto !important; + cursor: pointer !important; + transition: filter 0.2s ease !important; + position: relative !important; +} + +/* 模糊元素的悬停效果 */ +.blurtext-blurred:hover::after { + content: '点击取消模糊' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%) !important; + background: rgba(102, 126, 234, 0.95) !important; + color: white !important; + padding: 4px 8px !important; + border-radius: 4px !important; + font-size: 12px !important; + white-space: nowrap !important; + z-index: 999999 !important; + pointer-events: none !important; + filter: none !important; +} + +/* 模糊模式下的鼠标样式 */ +body.blurtext-mode * { + cursor: crosshair !important; +} + +/* 模糊模式提示 */ +.blurtext-hint { + position: fixed !important; + top: 20px !important; + left: 50% !important; + transform: translateX(-50%) !important; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; + color: white !important; + padding: 12px 24px !important; + border-radius: 24px !important; + font-size: 14px !important; + font-weight: 500 !important; + z-index: 9999999 !important; + box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4) !important; + animation: blurtext-slideDown 0.3s ease !important; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important; +} + +@keyframes blurtext-slideDown { + from { + opacity: 0; + transform: translateX(-50%) translateY(-10px); + } + to { + opacity: 1; + transform: translateX(-50%) translateY(0); + } +} + +/* 高亮效果(鼠标悬停在可模糊元素上) */ +.blurtext-highlight { + outline: 2px dashed #667eea !important; + outline-offset: 2px !important; + background: rgba(102, 126, 234, 0.1) !important; +} + +/* 文本选择模式的模糊按钮 */ +.blurtext-blur-button { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; + color: white !important; + padding: 10px 20px !important; + border-radius: 20px !important; + font-size: 14px !important; + font-weight: 500 !important; + cursor: pointer !important; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4) !important; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important; + animation: blurtext-buttonPop 0.2s ease !important; + user-select: none !important; + white-space: nowrap !important; + border: none !important; + transition: all 0.3s ease !important; +} + +.blurtext-blur-button:hover { + transform: translateX(-50%) scale(1.05) !important; + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.5) !important; +} + +.blurtext-blur-button:active { + transform: translateX(-50%) scale(0.95) !important; +} + +@keyframes blurtext-buttonPop { + from { + opacity: 0; + transform: translateX(-50%) scale(0.8); + } + to { + opacity: 1; + transform: translateX(-50%) scale(1); + } +} + +/* 文本选择模式包裹的元素 */ +.blurtext-selection-wrapped { + display: inline !important; +} diff --git a/content.js b/content.js new file mode 100644 index 0000000..fde1276 --- /dev/null +++ b/content.js @@ -0,0 +1,372 @@ +// content.js - 核心功能实现 +(function() { + 'use strict'; + + console.log('[BlurText] Content script loaded'); + + let isBlurMode = false; + let blurMode = 'element'; // 'element' or 'selection' + let blurIntensity = 10; + let blurredElements = new Set(); + let hintElement = null; + let blurButton = null; // 浮动模糊按钮 + + // 初始化:从存储中加载配置 + chrome.storage.local.get(['blurIntensity'], (result) => { + if (result.blurIntensity) { + blurIntensity = result.blurIntensity; + console.log('[BlurText] Loaded blur intensity:', blurIntensity); + } + }); + + // 监听来自 popup 的消息 + chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + console.log('[BlurText] Received message:', request); + + if (request.action === 'toggleBlurMode') { + isBlurMode = request.enabled; + blurMode = request.mode || 'element'; + blurIntensity = request.intensity || 10; + + console.log('[BlurText] Toggle blur mode:', isBlurMode, 'mode:', blurMode, 'intensity:', blurIntensity); + + if (isBlurMode) { + enableBlurMode(); + } else { + disableBlurMode(); + } + } else if (request.action === 'clearAll') { + console.log('[BlurText] Clear all blurs'); + clearAllBlurs(); + } else if (request.action === 'updateIntensity') { + blurIntensity = request.intensity; + console.log('[BlurText] Update intensity:', blurIntensity); + updateAllBlurIntensity(); + } else if (request.action === 'switchMode') { + blurMode = request.mode; + console.log('[BlurText] Switch mode:', blurMode); + updateModeUI(); + } + }); + + // 启用模糊模式 + function enableBlurMode() { + console.log('[BlurText] Enabling blur mode, mode:', blurMode); + + const modeText = blurMode === 'selection' ? '文本选择模式 - 拖动选择文字后点击模糊按钮' : '元素模式 - 点击元素进行模糊'; + showHint(`模糊模式已开启 - ${modeText},按 ESC 退出`); + + // 根据模式添加对应的样式和事件 + if (blurMode === 'element') { + document.body.classList.add('blurtext-mode'); + document.addEventListener('click', handleClick, true); + document.addEventListener('mouseover', handleMouseOver, true); + document.addEventListener('mouseout', handleMouseOut, true); + } else if (blurMode === 'selection') { + // 文本选择模式不需要 crosshair 光标 + document.addEventListener('mouseup', handleTextSelection, true); + } + + // 键盘事件对两种模式都需要 + document.addEventListener('keydown', handleKeydown, true); + + console.log('[BlurText] Event listeners attached'); + } + + // 禁用模糊模式 + function disableBlurMode() { + document.body.classList.remove('blurtext-mode'); + hideHint(); + hideBlurButton(); + + // 移除所有事件监听 + document.removeEventListener('click', handleClick, true); + document.removeEventListener('keydown', handleKeydown, true); + document.removeEventListener('mouseover', handleMouseOver, true); + document.removeEventListener('mouseout', handleMouseOut, true); + document.removeEventListener('mouseup', handleTextSelection, true); + + // 清除所有高亮和预览 + removeAllHighlights(); + } + + // 更新模式UI + function updateModeUI() { + if (!isBlurMode) return; + + console.log('[BlurText] Switching mode to:', blurMode); + + // 先移除所有旧的事件监听和样式 + document.body.classList.remove('blurtext-mode'); + document.removeEventListener('click', handleClick, true); + document.removeEventListener('mouseover', handleMouseOver, true); + document.removeEventListener('mouseout', handleMouseOut, true); + document.removeEventListener('mouseup', handleTextSelection, true); + + // 清除旧模式的UI元素 + hideBlurButton(); + removeAllHighlights(); + + // 根据新模式添加事件监听和样式 + if (blurMode === 'element') { + document.body.classList.add('blurtext-mode'); + document.addEventListener('click', handleClick, true); + document.addEventListener('mouseover', handleMouseOver, true); + document.addEventListener('mouseout', handleMouseOut, true); + showHint('已切换到元素模式 - 点击元素进行模糊', 3000); + } else if (blurMode === 'selection') { + // 文本选择模式不需要 crosshair 光标 + document.addEventListener('mouseup', handleTextSelection, true); + showHint('已切换到文本选择模式 - 拖动选择文字后点击模糊按钮', 3000); + } + + console.log('[BlurText] Mode switched successfully'); + } + + // 处理点击事件 + function handleClick(e) { + console.log('[BlurText] Click detected, isBlurMode:', isBlurMode, 'blurMode:', blurMode); + + if (!isBlurMode || blurMode !== 'element') return; + + // 阻止默认行为 + e.preventDefault(); + e.stopPropagation(); + + let target = e.target; + console.log('[BlurText] Target element:', target.tagName, target.className, 'text:', target.textContent?.substring(0, 20)); + + // 如果是提示元素,忽略 + if (target.classList.contains('blurtext-hint')) { + console.log('[BlurText] Ignored hint element'); + return; + } + + // 切换模糊状态 + toggleBlur(target); + } + + // 处理键盘事件(ESC 退出) + function handleKeydown(e) { + if (e.key === 'Escape' && isBlurMode) { + isBlurMode = false; + disableBlurMode(); + + // 通知 popup + chrome.runtime.sendMessage({ action: 'blurModeDisabled' }); + } + } + + // 处理文本选择(文本选择模式) + function handleTextSelection(e) { + if (!isBlurMode || blurMode !== 'selection') return; + + // 避免点击模糊按钮时触发 + if (e.target.classList.contains('blurtext-blur-button')) { + return; + } + + const selection = window.getSelection(); + const selectedText = selection.toString().trim(); + + console.log('[BlurText] Text selection:', selectedText); + + if (selectedText.length > 0) { + // 显示模糊按钮 + showBlurButton(selection); + } else { + // 没有选中文本,隐藏按钮 + hideBlurButton(); + } + } + + // 显示模糊按钮 + function showBlurButton(selection) { + // 移除旧按钮 + hideBlurButton(); + + // 获取选区的位置 + const range = selection.getRangeAt(0); + const rect = range.getBoundingClientRect(); + + // 创建模糊按钮 + blurButton = document.createElement('div'); + blurButton.className = 'blurtext-blur-button'; + blurButton.textContent = '🔒 模糊选中文本'; + blurButton.style.position = 'fixed'; + blurButton.style.left = `${rect.left + rect.width / 2}px`; + blurButton.style.top = `${rect.bottom + 10}px`; + blurButton.style.transform = 'translateX(-50%)'; + blurButton.style.zIndex = '2147483647'; + + // 点击按钮模糊文本 + blurButton.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + blurSelectedText(); + }); + + document.body.appendChild(blurButton); + } + + // 隐藏模糊按钮 + function hideBlurButton() { + if (blurButton && blurButton.parentNode) { + blurButton.parentNode.removeChild(blurButton); + blurButton = null; + } + } + + // 模糊选中的文本 + function blurSelectedText() { + const selection = window.getSelection(); + if (!selection.rangeCount) return; + + try { + const range = selection.getRangeAt(0); + + // 创建 span 包裹选中的文本 + const span = document.createElement('span'); + span.className = 'blurtext-blurred blurtext-selection-wrapped'; + span.style.setProperty('--blur-intensity', `${blurIntensity}px`); + + // 包裹选中的内容 + range.surroundContents(span); + + // 添加到模糊元素集合 + blurredElements.add(span); + + console.log('[BlurText] Text selection blurred, total elements:', blurredElements.size); + + // 清除选择 + selection.removeAllRanges(); + + // 隐藏按钮 + hideBlurButton(); + + // 显示提示 + showHint('文本已模糊', 2000); + } catch (error) { + console.error('[BlurText] Error blurring selection:', error); + showHint('无法模糊该选区(可能包含复杂的HTML结构)', 3000); + hideBlurButton(); + } + } + + // 鼠标悬停高亮 + function handleMouseOver(e) { + if (!isBlurMode || blurMode !== 'element') return; + + const target = e.target; + if (target.classList.contains('blurtext-hint') || + target.classList.contains('blurtext-blurred')) { + return; + } + + // 移除之前的高亮 + removeAllHighlights(); + + // 直接高亮元素 + target.classList.add('blurtext-highlight'); + } + + // 移除所有高亮 + function removeAllHighlights() { + const highlighted = document.querySelectorAll('.blurtext-highlight'); + highlighted.forEach(el => { + el.classList.remove('blurtext-highlight'); + }); + } + + // 鼠标移出取消高亮 + function handleMouseOut(e) { + if (!isBlurMode || blurMode !== 'element') return; + + // 延迟移除,避免在元素间移动时闪烁 + setTimeout(() => { + // 检查鼠标是否还在模糊模式下的元素上 + const hoveredElement = document.elementFromPoint(e.clientX, e.clientY); + if (!hoveredElement || + hoveredElement.classList.contains('blurtext-hint') || + hoveredElement.classList.contains('blurtext-blurred')) { + return; + } + + // 如果鼠标不在任何高亮元素上,清除所有高亮 + const highlighted = document.querySelector('.blurtext-highlight:hover'); + if (!highlighted) { + removeAllHighlights(); + } + }, 100); + } + + // 切换元素模糊状态 + function toggleBlur(element) { + if (blurredElements.has(element)) { + // 取消模糊 + console.log('[BlurText] Removing blur from element'); + element.classList.remove('blurtext-blurred'); + element.style.removeProperty('--blur-intensity'); + blurredElements.delete(element); + } else { + // 添加模糊 + console.log('[BlurText] Adding blur to element, intensity:', blurIntensity); + element.classList.add('blurtext-blurred'); + element.style.setProperty('--blur-intensity', `${blurIntensity}px`); + blurredElements.add(element); + } + console.log('[BlurText] Total blurred elements:', blurredElements.size); + } + + // 清除所有模糊 + function clearAllBlurs() { + blurredElements.forEach(element => { + element.classList.remove('blurtext-blurred'); + element.style.removeProperty('--blur-intensity'); + }); + blurredElements.clear(); + + // 如果在模糊模式下,显示提示 + if (isBlurMode) { + showHint('已清除所有模糊效果', 2000); + } + } + + // 更新所有已模糊元素的强度 + function updateAllBlurIntensity() { + blurredElements.forEach(element => { + element.style.setProperty('--blur-intensity', `${blurIntensity}px`); + }); + } + + // 显示提示 + function showHint(message, duration = null) { + // 移除旧提示 + hideHint(); + + // 创建新提示 + hintElement = document.createElement('div'); + hintElement.className = 'blurtext-hint'; + hintElement.textContent = message; + document.body.appendChild(hintElement); + + // 如果指定了持续时间,自动隐藏 + if (duration) { + setTimeout(() => { + hideHint(); + }, duration); + } + } + + // 隐藏提示 + function hideHint() { + if (hintElement && hintElement.parentNode) { + hintElement.parentNode.removeChild(hintElement); + hintElement = null; + } + } + + // 页面加载完成后,恢复之前的模糊状态(未来功能) + // 这里可以添加持久化存储功能 + +})(); diff --git a/icon-generator.html b/icon-generator.html new file mode 100644 index 0000000..0a9da09 --- /dev/null +++ b/icon-generator.html @@ -0,0 +1,173 @@ + + + + + + BlurText 图标生成器 + + + +

🔒 BlurText 图标生成器

+

右键点击图标 → 另存为图像 → 保存到 icons 文件夹

+ +
+
+ + + + + + + + + + + + +
16x16
+ +
+ +
+ + + + + + + + + + + + +
32x32
+ +
+ +
+ + + + + + + + + + + + +
48x48
+ +
+ +
+ + + + + + + + + + + + +
128x128
+ +
+
+ +
+

📝 使用说明

+
    +
  1. 方法一(推荐):右键点击每个图标 → 另存为图像 → 保存到 icons/ 文件夹,文件名分别为 icon16.png, icon32.png, icon48.png, icon128.png
  2. +
  3. 方法二:点击每个图标下方的"下载"按钮,自动下载 PNG 文件
  4. +
  5. 方法三:使用在线工具将 SVG 转换为 PNG: +
      +
    • 访问 CloudConvert
    • +
    • 上传 SVG 图标,设置对应尺寸,转换为 PNG
    • +
    +
  6. +
+

注意:图标文件必须保存在 icons/ 文件夹中,并使用正确的文件名。

+
+ + + + diff --git a/icons/icon128.png b/icons/icon128.png new file mode 100644 index 0000000..cf9df90 Binary files /dev/null and b/icons/icon128.png differ diff --git a/icons/icon16.png b/icons/icon16.png new file mode 100644 index 0000000..21b26be Binary files /dev/null and b/icons/icon16.png differ diff --git a/icons/icon32.png b/icons/icon32.png new file mode 100644 index 0000000..ea0d078 Binary files /dev/null and b/icons/icon32.png differ diff --git a/icons/icon48.png b/icons/icon48.png new file mode 100644 index 0000000..c89d973 Binary files /dev/null and b/icons/icon48.png differ diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..23634dc --- /dev/null +++ b/manifest.json @@ -0,0 +1,33 @@ +{ + "manifest_version": 3, + "name": "BlurText - 文字模糊保护", + "version": "1.0.0", + "description": "屏幕分享和录制时一键模糊敏感文字信息,保护隐私安全", + "permissions": [ + "activeTab", + "storage" + ], + "action": { + "default_popup": "popup.html", + "default_icon": { + "16": "icons/icon16.png", + "32": "icons/icon32.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } + }, + "content_scripts": [ + { + "matches": [""], + "js": ["content.js"], + "css": ["content.css"], + "run_at": "document_end" + } + ], + "icons": { + "16": "icons/icon16.png", + "32": "icons/icon32.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } +} diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..a1651df --- /dev/null +++ b/popup.html @@ -0,0 +1,282 @@ + + + + + + BlurText + + + +
+

🔒 BlurText

+

屏幕分享隐私保护

+ +
+ 💡 点击下方按钮开始使用 +
+ +
+ +
+ + +
+
+ +
+ +
+ + 10px +
+
+ +
+ + +
+ +
+ 使用方法:
+ + 元素模式:
+ 1. 点击"开启模糊模式"
+ 2. 鼠标悬停元素查看高亮
+ 3. 点击元素进行模糊
+ 4. 再次点击取消模糊 +
+
+
+ + + + diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..037b3c2 --- /dev/null +++ b/popup.js @@ -0,0 +1,168 @@ +// popup.js - 弹出窗口逻辑 +let isBlurMode = false; +let currentMode = 'element'; // 'element' or 'selection' + +console.log('[BlurText] Popup script loaded'); + +// 获取页面元素 +const toggleBtn = document.getElementById('toggleBlur'); +const toggleText = document.getElementById('toggleText'); +const clearAllBtn = document.getElementById('clearAll'); +const blurIntensitySlider = document.getElementById('blurIntensity'); +const intensityValue = document.getElementById('intensityValue'); +const statusDiv = document.getElementById('status'); +const modeElementBtn = document.getElementById('modeElement'); +const modeSelectionBtn = document.getElementById('modeSelection'); +const usageTip = document.getElementById('usageTip'); + +// 从存储中加载模糊强度 +chrome.storage.local.get(['blurIntensity'], (result) => { + if (result.blurIntensity) { + blurIntensitySlider.value = result.blurIntensity; + intensityValue.textContent = result.blurIntensity + 'px'; + } +}); + +// 模糊强度滑块变化 +blurIntensitySlider.addEventListener('input', (e) => { + const value = e.target.value; + intensityValue.textContent = value + 'px'; + + // 保存到存储 + chrome.storage.local.set({ blurIntensity: value }); + + // 通知 content script 更新强度 + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + chrome.tabs.sendMessage(tabs[0].id, { + action: 'updateIntensity', + intensity: value + }); + }); +}); + +// 模式切换 +[modeElementBtn, modeSelectionBtn].forEach(btn => { + btn.addEventListener('click', () => { + const mode = btn.dataset.mode; + currentMode = mode; + + // 更新UI + document.querySelectorAll('.mode-btn').forEach(b => b.classList.remove('active')); + btn.classList.add('active'); + + // 更新使用提示 + updateUsageTip(mode); + + // 如果已经在模糊模式中,通知 content script 切换模式 + if (isBlurMode) { + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + chrome.tabs.sendMessage(tabs[0].id, { + action: 'switchMode', + mode: mode + }); + }); + } + }); +}); + +// 更新使用提示 +function updateUsageTip(mode) { + if (mode === 'element') { + usageTip.innerHTML = ` + 元素模式:
+ 1. 点击"开启模糊模式"
+ 2. 鼠标悬停元素查看高亮
+ 3. 点击元素进行模糊
+ 4. 再次点击取消模糊 + `; + } else { + usageTip.innerHTML = ` + 文本选择模式:
+ 1. 点击"开启模糊模式"
+ 2. 拖动鼠标选择文本
+ 3. 点击浮动按钮模糊文本
+ 4. 可多次选择和模糊 + `; + } +} + +// 切换模糊模式 +toggleBtn.addEventListener('click', async () => { + try { + console.log('[BlurText] Toggle button clicked'); + const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); + + if (!tab) { + console.error('[BlurText] No active tab found'); + statusDiv.innerHTML = '⚠️ 无法获取当前标签页'; + return; + } + + isBlurMode = !isBlurMode; + console.log('[BlurText] New blur mode state:', isBlurMode); + + // 发送消息给 content script + chrome.tabs.sendMessage(tab.id, { + action: 'toggleBlurMode', + enabled: isBlurMode, + mode: currentMode, + intensity: blurIntensitySlider.value + }, (response) => { + if (chrome.runtime.lastError) { + console.error('[BlurText] Error sending message:', chrome.runtime.lastError); + statusDiv.innerHTML = '⚠️ 请刷新页面后重试'; + statusDiv.className = 'status'; + isBlurMode = !isBlurMode; // 恢复状态 + } else { + console.log('[BlurText] Message sent successfully'); + } + }); + + // 更新 UI + updateUI(); + } catch (error) { + console.error('[BlurText] Error in toggle:', error); + statusDiv.innerHTML = ' 发生错误,请重试'; + } +}); + +// 清除所有模糊 +clearAllBtn.addEventListener('click', async () => { + const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); + + chrome.tabs.sendMessage(tab.id, { + action: 'clearAll' + }); + + statusDiv.innerHTML = ' 已清除所有模糊效果'; + statusDiv.className = 'status'; + + setTimeout(() => { + statusDiv.innerHTML = '💡 点击下方按钮开始使用'; + }, 2000); +}); + +// 更新 UI 状态 +function updateUI() { + if (isBlurMode) { + toggleText.textContent = '关闭模糊模式'; + toggleBtn.classList.remove('btn-primary'); + toggleBtn.classList.add('btn-secondary'); + statusDiv.innerHTML = ' 模糊模式已开启,点击网页文字进行模糊'; + statusDiv.className = 'status active'; + } else { + toggleText.textContent = '开启模糊模式'; + toggleBtn.classList.add('btn-primary'); + toggleBtn.classList.remove('btn-secondary'); + statusDiv.innerHTML = '💡 点击下方按钮开始使用'; + statusDiv.className = 'status'; + } +} + +// 监听来自 content script 的消息 +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === 'blurModeDisabled') { + isBlurMode = false; + updateUI(); + } +}); diff --git a/test-textnode.html b/test-textnode.html new file mode 100644 index 0000000..abb02e3 --- /dev/null +++ b/test-textnode.html @@ -0,0 +1,205 @@ + + + + + + 纯文本节点测试 + + + +
+

🧪 纯文本节点测试

+

测试 BlurText 自动处理纯文本节点的能力

+ +
+ ✨ 新功能:现在 BlurText 可以自动处理纯文本节点!
+ 当你点击纯文本时,扩展会自动将其包裹在 <span> 中,然后模糊。 +
+ +
+

测试 1:纯文本节点(自动处理)智能

+
+

姓名:李四

+

年龄:28

+

城市:上海

+
+

💡 测试方法:

+
    +
  • 点击"李四" → 应该自动识别并只模糊"李四"
  • +
  • 点击"28" → 应该只模糊数字
  • +
  • 点击"上海" → 应该只模糊城市名
  • +
  • 点击"姓名:"标签 → 模糊标签
  • +
+
+ +
+

测试 2:混合文本(智能分割)智能

+
+

手机号:138-8888-9999

+

邮箱:user@example.com

+

API Key: sk-1234567890abcdefghijk

+
+

💡 测试方法:

+
    +
  • 点击"138-8888-9999" → 自动识别手机号并单独模糊
  • +
  • 点击"user@example.com" → 自动识别邮箱并模糊
  • +
  • 点击"sk-1234..." → 自动识别密钥并模糊
  • +
  • 点击"手机号:"文字 → 模糊整行
  • +
+
+ +
+

测试 3:复杂场景

+
+

用户 张三 的手机号是 186-0000-1234,邮箱是 zhangsan@company.com

+
+

💡 测试方法:

+
    +
  • 点击"张三" → 只模糊名字
  • +
  • 点击"186-0000-1234" → 只模糊手机号
  • +
  • 点击"zhangsan@company.com" → 只模糊邮箱
  • +
  • 点击"用户"或"的手机号是" → 模糊整行
  • +
+
+ +
+

测试 4:列表中的纯文本

+
+
    +
  • 订单号 ORD-20250101-001
  • +
  • 金额 ¥1,288.00
  • +
  • 地址 北京市朝阳区某某街道123号
  • +
+
+

💡 测试方法:

+
    +
  • 点击订单号 → 自动识别并模糊
  • +
  • 点击金额 → 模糊数字
  • +
  • 点击地址 → 模糊地址
  • +
+
+ +
+ 🔍 工作原理:

+ 1. 检测文本节点
+ 当你点击纯文本时,使用 document.caretRangeFromPoint() 检测是否点在文本节点上

+ + 2. 智能识别模式
+ 扫描文本内容,识别常见的敏感信息模式:
+ • 手机号:/\d{3,}[-\d]*/
+ • 邮箱:/[\w\.-]+@[\w\.-]+\.\w+/
+ • Token/密钥:/[a-zA-Z0-9_-]{10,}/

+ + 3. 自动包裹
+ 如果识别到敏感信息,自动创建 <span> 包裹该部分
+ 如果没识别到特定模式,包裹整个文本节点

+ + 4. 应用模糊
+ 对新创建的 <span> 应用模糊效果 +
+ +
+ ✅ 预期效果:
+ • 点击敏感信息(手机号、邮箱等)→ 只模糊该信息
+ • 点击普通文字 → 模糊整个文本节点或整行
+ • 支持在同一行中选择性模糊不同部分
+ • 不破坏原始 HTML 结构(只在需要时添加 span) +
+ +
+ 💡 Console 日志:
+ 按 F12 打开控制台,点击文字时会看到:
+ • [BlurText] Detected text node: ...
+ • [BlurText] Found sensitive value: ...
+ • [BlurText] Wrapped text node in span +
+
+ + diff --git a/test.html b/test.html new file mode 100644 index 0000000..0fe67bb --- /dev/null +++ b/test.html @@ -0,0 +1,228 @@ + + + + + + BlurText 测试页面 + + + +
+

🔒 BlurText 测试页面

+

使用这个页面测试模糊功能是否正常工作

+ +
+ 📖 测试步骤: +
    +
  1. 点击浏览器工具栏的 BlurText 图标
  2. +
  3. 点击弹出窗口中的 "开启模糊模式" 按钮
  4. +
  5. 页面顶部应该显示提示:"模糊模式已开启"
  6. +
  7. 鼠标悬停在下方文字上,应该有蓝色虚线框高亮
  8. +
  9. 点击任意文字,应该变模糊
  10. +
  11. 再次点击模糊的文字,应该取消模糊
  12. +
  13. ESC 键退出模糊模式
  14. +
+
+ +
+

📝 测试区域 1:普通文本

+
+

这是一段普通的文本内容,你可以点击这段文字来测试模糊功能。

+

模糊功能应该可以立即生效,不需要屏幕录制或分享。

+
+
+ +
+

🔐 测试区域 2:敏感信息模拟

+
+
+ API Key: sk-1234567890abcdefghijklmnopqrstuvwxyz +
+
+ 手机号: 138-0000-1234 +
+
+ 邮箱: example@company.com +
+
+ 密码: MyS3cur3P@ssw0rd! +
+
+
+ +
+

📊 测试区域 3:卡片内容

+
+ 用户信息 +

姓名:张三

+

身份证:110101199001011234

+

银行卡:6222 0000 1111 2222

+
+
+ 订单信息 +

订单号:ORD-2025-001234

+

金额:¥1,288.00

+

地址:北京市朝阳区某某街道123号

+
+
+ +
+

📋 测试区域 4:列表内容

+
+
    +
  • 项目 A - 配置文件路径:/etc/config/secret.yml
  • +
  • 项目 B - 数据库连接:mysql://user:password@localhost:3306
  • +
  • 项目 C - 访问令牌:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  • +
  • 项目 D - 私钥文件:~/.ssh/id_rsa
  • +
+
+
+ +
+ ⚠️ 故障排查: +

如果功能不工作,请检查:

+
    +
  • 扩展是否正确安装(查看 chrome://extensions/
  • +
  • 扩展是否启用(开关是否打开)
  • +
  • 是否显示任何错误(右键扩展图标 → 检查弹出窗口)
  • +
  • 刷新页面后重试
  • +
  • 打开浏览器控制台(F12)查看是否有错误信息
  • +
+
+ +
+ ✅ 预期行为: +
    +
  • 开启模糊模式后,页面顶部显示紫色提示条
  • +
  • 鼠标移动到文字上,出现蓝色虚线边框高亮
  • +
  • 点击文字后,该文字变模糊(毛玻璃效果)
  • +
  • 鼠标悬停在已模糊的文字上,显示"点击取消模糊"提示
  • +
  • 再次点击已模糊文字,模糊效果消失
  • +
+
+
+ + + + diff --git a/usage-guide.html b/usage-guide.html new file mode 100644 index 0000000..38c2822 --- /dev/null +++ b/usage-guide.html @@ -0,0 +1,279 @@ + + + + + + BlurText 使用说明 + + + +
+

🔒 BlurText 使用说明

+ +

⚠️ 重要限制

+
+ 注意:BlurText 只能模糊 HTML 元素,不能直接模糊纯文本节点。
+ 如果你想要单独模糊某个值(如手机号、姓名),该值必须包裹在 HTML 标签中(如 <span>)。 +
+ +

✅ 正确的 HTML 结构

+ +
+
示例 1:可以单独模糊值
+
+

姓名:张三

+
+
<p>
+  <strong>姓名:</strong>
+  <span>张三</span>
+</p>
+

效果:

+
    +
  • 鼠标移到"姓名:"→ 高亮 <strong> 标签
  • +
  • 鼠标移到"张三" → 高亮 <span> 标签
  • +
  • 点击"姓名:"→ 模糊标签
  • +
  • 点击"张三" → 只模糊"张三" 推荐
  • +
  • 点击整行空白处 → 模糊整个 <p>
  • +
+
+ +
+
示例 2:复杂结构
+
+
+ 手机号:138-0000-1234 +
+
+
<div class="sensitive-info">
+  <strong>手机号:</strong>
+  <span>138-0000-1234</span>
+</div>
+

效果:

+
    +
  • 点击"手机号:"→ 模糊标签
  • +
  • 点击"138-0000-1234" → 只模糊数字
  • +
  • 点击背景区域 → 模糊整个 div
  • +
+
+ +

❌ 错误的 HTML 结构

+ +
+
示例 3:无法单独模糊值
+
+

姓名:张三

+
+
<p>
+  <strong>姓名:</strong>
+  张三
+</p>
+

问题:

+
    +
  • "张三"是纯文本节点,不在任何标签里
  • +
  • 鼠标移到"张三"上,实际高亮的是整个 <p>
  • +
  • 点击"张三" → 模糊整个 <p>(包括"姓名:")
  • +
  • 无法单独模糊"张三" 不推荐
  • +
+
+ +
+ 💡 解决方案:
+ 如果你在自己的网页上使用 BlurText,请确保需要单独模糊的内容包裹在标签中: +
// 错误 ❌
+<p>手机号:138-0000-1234</p>
+
+// 正确 ✅
+<p>手机号:<span>138-0000-1234</span></p>
+
+ +

🎯 最佳实践

+ +
+
推荐的 HTML 结构模板
+
<!-- 表单字段 -->
+<div class="field">
+  <label>姓名</label>
+  <span class="value">张三</span>
+</div>
+
+<!-- 列表项 -->
+<ul>
+  <li>
+    <strong>API Key:</strong>
+    <code>sk-1234567890abcdef</code>
+  </li>
+</ul>
+
+<!-- 表格 -->
+<table>
+  <tr>
+    <td>手机号</td>
+    <td><span>138-0000-1234</span></td>
+  </tr>
+</table>
+
+ +

🔧 实际使用技巧

+ +
    +
  1. 识别 HTML 结构: +
      +
    • 按 F12 打开开发者工具
    • +
    • 使用元素选择器(左上角箭头图标)
    • +
    • 点击网页上的内容,查看 HTML 结构
    • +
    • 如果值在独立标签里,就可以单独模糊
    • +
    +
  2. + +
  3. 灵活使用模糊范围: +
      +
    • 如果无法单独模糊值,模糊整行或整个区块也能达到目的
    • +
    • 使用鼠标悬停预览,看蓝色边框高亮的是哪个元素
    • +
    • 根据高亮范围决定是否点击
    • +
    +
  4. + +
  5. 对于第三方网站: +
      +
    • 大部分网站的表单、表格、列表都有良好的结构
    • +
    • 现代网站通常会把数据包裹在 <span> 或其他标签中
    • +
    • 如果遇到无法单独模糊的情况,模糊整行即可
    • +
    +
  6. +
+ +
+ 📌 总结:
+ BlurText 的粒度取决于网页的 HTML 结构。结构越清晰(标签层级越细),模糊控制就越精确。这是浏览器扩展的技术限制,无法绕过。 +
+ +

🧪 测试建议

+

打开 test.html 测试页面,我已经更新了 HTML 结构,现在可以:

+
    +
  • ✅ 单独模糊"138-0000-1234"
  • +
  • ✅ 单独模糊"张三"
  • +
  • ✅ 单独模糊各种敏感信息
  • +
  • ✅ 或者模糊整行、整个区块
  • +
+ +
+ +