au-text-highlight
Version:
3行代码实现划词相关功能、关键字高亮、选区检测等功能。附带React版本划词popover组件。专为解决划词翻译,划词评论,web文本高亮等这类需求!目前再探索完善。
416 lines (351 loc) • 11.5 kB
Markdown
# au-text-highlight
**中文 | [English](README-EN.md)**
正式版已发布, 请必须使用1.1.51以上版本
3行代码实现划词相关功能、关键字高亮、选区检测等功能。附带React版本划词popover组件。专为解决划词翻译,划词评论,web文本高亮等这类需求!目前再探索完善,如有其他相关需求以及bug请提供issue或者发邮箱(aurora.coder.zqf@gmail.com)
## 项目背景
在现代Web应用中,文本高亮、划词翻译、关键字搜索等功能越来越常见。本模块提供了一套完整的解决方案,包括:
- 🎯 **文本选区检测** - 精确获取用户划词选中的文本位置
- 🌈 **智能高亮** - 自动高亮指定文本区域,支持自定义样式
- 💬 **划词弹窗** - 选区后出现React popover组件
- 🔧 **高度可定制** - 支持样式、行为、交互的完全自定义
- 📝 **关键字匹配** - 高效匹配文本中的关键词位置
## 安装
```bash
npm install au-text-highlight
```
## 核心功能
### 1. 关键字匹配与位置获取
提取文本中关键词的精确位置,支持单个关键词或关键词数组。
```javascript
import { auExtractText } from 'au-text-highlight'
// 单个关键词匹配
const result1 = auExtractText({
text: 'GPT是一种神奇的AI技术,GPT正在改变世界',
keywords: 'GPT'
})
// 返回: [
// { keyword: 'GPT', start: 0, end: 3 },
// { keyword: 'GPT', start: 15, end: 18 }
// ]
// 多个关键词匹配
const result2 = auExtractText({
text: 'JavaScript和TypeScript都是很棒的语言',
keywords: ['JavaScript', 'TypeScript']
})
// 返回: [
// { keyword: 'JavaScript', start: 0, end: 10 },
// { keyword: 'TypeScript', start: 11, end: 21 }
// ]
```
### 2. 文本选区检测
获取用户选中文本的位置信息,用于后续的高亮或其他操作。
```javascript
import { getSelectionRange, getSelectionRangeContent } from 'au-text-highlight'
// 获取选区的起始和结束位置
const containerElement = document.getElementById('text-container')
const [startIndex, endIndex] = getSelectionRange(containerElement)
// 获取选区内容和Selection对象
const { content, section } = getSelectionRangeContent()
console.log('选中的文本:', content)
```
### 3. 文本高亮
根据位置信息自动高亮文本,支持自定义样式和唯一标识。
```javascript
import { sectionRangeHighlight } from 'au-text-highlight'
const containerElement = document.getElementById('text-container')
// 基础高亮
sectionRangeHighlight(containerElement, [
{ start: 0, end: 5 },
{ start: 10, end: 15 }
])
// 带唯一标识的高亮(便于后续操作)
sectionRangeHighlight(containerElement, [
{ start: 0, end: 5, gid: 'highlight-1' },
{ start: 10, end: 15, gid: 'highlight-2' }
])
```
**高亮样式说明:**
- 高亮元素使用 `<span>` 标签包裹
- 默认class名称:`word_comment_mark`
- 包含无障碍属性:`role="text"` 和 `aria-label="高亮内容"`
- 支持通过gid参数设置唯一id,便于后续删除或修改
**自定义高亮样式:**
```css
.word_comment_mark {
background-color: #ffeb3b;
padding: 2px 4px;
border-radius: 3px;
border: 1px solid #ffc107;
}
/* 或者通过id选择器自定义特定高亮 */
#highlight-1 {
background-color: #e3f2fd;
border: 1px solid #2196f3;
}
```
<!-- ### 4. 原生JavaScript划词弹窗
使用原生JavaScript实现的划词弹窗功能。
```javascript
import { DrawWordConstituencyPopover } from 'au-text-highlight'
// 创建弹窗HTML元素
const popoverElement = document.createElement('div')
popoverElement.id = 'my-popover'
popoverElement.innerHTML = `
<div style="background: white; border: 1px solid #ccc; padding: 10px; border-radius: 5px;">
<button onclick="translate()">翻译</button>
<button onclick="search()">搜索</button>
</div>
`
// 初始化弹窗
const popover = new DrawWordConstituencyPopover('my-popover', {
distance: 10 // 弹窗距离选区的距离
})
``` -->
## React组件
### 1. AuSelectionPopover 组件
React版本的文本选区弹窗组件,支持完全自定义内容。
```tsx
import React from 'react'
import { ReactAuSelectionPopover } from 'au-text-highlight'
function MyComponent() {
const handleShow = (position) => {
console.log('选中文本:', position.text)
}
const handleHide = () => {
console.log('弹窗隐藏')
}
return (
<div>
<div id="text-container">
选择这段文本试试看,会弹出自定义的操作面板。
</div>
<ReactAuSelectionPopover
distance={10}
container={document.getElementById('text-container')}
onShow={handleShow}
onHide={handleHide}
className="my-popover"
style={{
backgroundColor: 'white',
border: '1px solid #e5e7eb',
borderRadius: '8px',
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
padding: '12px'
}}
>
<div>
<button onClick={() => alert('翻译功能')}>🌐 翻译</button>
<button onClick={() => alert('搜索功能')}>🔍 搜索</button>
<button onClick={() => alert('复制功能')}>📋 复制</button>
</div>
</ReactAuSelectionPopover>
</div>
)
}
```
**AuSelectionPopover Props:**
- `children`: React.ReactNode - 弹窗内容(必需)
- `distance`: number - 弹窗距离选区的距离,默认10px
- `className`: string - 自定义CSS类名
- `style`: React.CSSProperties - 自定义样式
- `container`: HTMLElement - 限定文本选区检测的容器元素
- `onShow`: (position) => void - 弹窗显示时的回调
- `onHide`: () => void - 弹窗隐藏时的回调
- `disabled`: boolean - 是否禁用弹窗,默认false
- `portal`: boolean - 是否使用Portal渲染,默认true
- `zIndex`: number - 弹窗层级,默认9999
### 2. useTextSelection Hook
用于文本选区检测的React Hook。
```tsx
import React from 'react'
import { useTextSelection } from 'au-text-highlight'
function MyComponent() {
const { selection, isSelecting, clearSelection } = useTextSelection({
delay: 100,
container: document.getElementById('text-container')
})
React.useEffect(() => {
if (selection) {
console.log('选中文本:', selection.text)
console.log('位置信息:', selection.x, selection.y)
}
}, [selection])
return (
<div>
<div id="text-container">
选择这段文本,控制台会输出选区信息。
</div>
<div>
状态:
{' '}
{isSelecting ? '选择中' : '未选择'}
{selection && (
<p>
选中:
{selection.text}
</p>
)}
<button onClick={clearSelection}>清除选区</button>
</div>
</div>
)
}
```
**useTextSelection 参数:**
- `delay`: number - 选区检测延迟时间,默认100ms
- `container`: HTMLElement - 限定检测范围的容器元素
**useTextSelection 返回值:**
- `selection`: TriggerPosition | null - 当前选区信息
- `isSelecting`: boolean - 是否正在选择文本
- `clearSelection`: () => void - 清除当前选区
- `getTriggerPosition`: () => TriggerPosition | null - 手动获取选区位置
## 完整示例
### 综合使用示例
```javascript
import {
auExtractText,
getSelectionRange,
sectionRangeHighlight
} from 'au-text-highlight'
// 1. 搜索并高亮关键词
function highlightKeywords(containerElement, keywords) {
const text = containerElement.textContent
const matches = auExtractText({ text, keywords })
// 高亮所有匹配的关键词
const positions = matches.map((match, index) => ({
start: match.start,
end: match.end,
gid: `keyword-${index}`
}))
sectionRangeHighlight(containerElement, positions)
}
// 2. 用户选区高亮
function highlightUserSelection(containerElement) {
const [start, end] = getSelectionRange(containerElement)
sectionRangeHighlight(containerElement, [
{ start, end, gid: 'user-selection' }
])
}
// 使用示例
const container = document.getElementById('article')
highlightKeywords(container, ['JavaScript', 'React', 'TypeScript'])
```
### React完整示例
```tsx
import React, { useRef, useState } from 'react'
import {
ReactAuSelectionPopover,
auExtractText,
sectionRangeHighlight
} from 'au-text-highlight'
function TextHighlightDemo() {
const [selectedText, setSelectedText] = useState('')
const containerRef = useRef<HTMLDivElement>(null)
const handleShow = (position) => {
setSelectedText(position.text)
}
const handleTranslate = () => {
alert(`翻译: ${selectedText}`)
}
const handleHighlight = () => {
if (containerRef.current) {
const text = containerRef.current.textContent
const matches = auExtractText({ text, keywords: selectedText })
const positions = matches.map((match, index) => ({
start: match.start,
end: match.end,
gid: `highlight-${index}`
}))
sectionRangeHighlight(containerRef.current, positions)
}
}
return (
<div>
<div ref={containerRef} className="text-content">
这是一段演示文本。选择任意文字会弹出操作菜单,
你可以翻译选中的文本,或者高亮页面中所有相同的词语。
</div>
<ReactAuSelectionPopover
container={containerRef.current}
onShow={handleShow}
style={{
backgroundColor: 'white',
border: '1px solid #ccc',
borderRadius: '6px',
padding: '8px',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
}}
>
<div className="popover-content">
<button onClick={handleTranslate}>🌐 翻译</button>
<button onClick={handleHighlight}>🎨 高亮相同词语</button>
</div>
</ReactAuSelectionPopover>
</div>
)
}
```
## 版本更新日志
- v1.1.5
- 修复react popover组件
- v1.1.0
- 正式版发布,完善文档,提供全面的划词评论,划词等功能的解决方案
- 增加react popover组件,用户划词选区后会出现popover组件
## 高级功能
未完待续,后续持续更新ing
<!-- ### 删除高亮
```javascript
// 删除特定高亮
function removeHighlight(gid) {
const element = document.getElementById(gid)
if (element) {
const parent = element.parentNode
while (element.firstChild) {
parent.insertBefore(element.firstChild, element)
}
parent.removeChild(element)
}
}
// 删除所有高亮
function removeAllHighlights() {
const highlights = document.querySelectorAll('.word_comment_mark')
highlights.forEach((element) => {
const parent = element.parentNode
while (element.firstChild) {
parent.insertBefore(element.firstChild, element)
}
parent.removeChild(element)
})
}
``` -->
<!--
### 自定义弹窗样式
```css
.au-text-highlight-popover {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 12px;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
color: white;
padding: 16px;
min-width: 200px;
animation: fadeInUp 0.3s ease-out;
}
fadeInUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
``` -->
## 浏览器兼容性
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
## 贡献
欢迎提交Issue和Pull Request!如果你有好的想法或发现了bug,请随时参与贡献。