import { HighlightCallbacks, HighlightOptions, HighlighterConfig } from "./type.js"; //#region src/modules/dom/highlighter/index.d.ts /** * 文本高亮器类 * * 提供在指定DOM元素中高亮显示关键词的功能,支持导航到不同的匹配项。 * 可以配置高亮样式、标签类型,并提供前进/后退导航功能。 * * @example * ```typescript * // 基本用法(单个关键词) * const container = document.getElementById('content') * const highlighter = new Highlighter(container) * highlighter.apply('搜索关键词') * * // 多个关键词高亮 * highlighter.apply(['JavaScript', 'TypeScript', 'React']) * * // 使用配置对象 * const highlighter = new Highlighter(container, { * highlightTag: 'span', * highlightClass: 'my-highlight', * activeClass: 'my-active', * skipTags: ['SCRIPT', 'STYLE', 'CODE'], * smartScroll: true, // 启用智能滚动 * scrollPadding: 100 // 设置视口内边距为100px * }) * * // 带回调的高级用法 * const highlighter = new Highlighter(container, { * highlightClass: 'search-result' * }, { * onHighlightApplied: (count, keywords) => { * console.log(`找到 ${count} 个 "${keywords}" 的匹配项`) * }, * onNavigate: (index, total, element) => { * console.log(`当前: ${index + 1}/${total}`) * } * }) * * // 高级选项(多个关键词) * highlighter.apply(['JavaScript', 'API'], { * caseSensitive: true, // 区分大小写 * wholeWord: true // 只匹配完整单词 * }) * * // 导航功能 * highlighter.next() // 下一个匹配项 * highlighter.previous() // 上一个匹配项 * highlighter.jumpTo(5) // 跳转到第6个匹配项 * ``` * * @public */ declare class Highlighter { private targetNode; private config; private callbacks; private highlights; private currentIndex; private currentKeywords; private currentPattern; /** * 创建一个新的高亮器实例 * * @param targetNode - 要进行高亮操作的目标DOM元素 * @param config - 高亮器配置选项 * @param callbacks - 事件回调函数 * * @example * ```typescript * const container = document.getElementById('content') * * // 使用默认配置 * const highlighter1 = new Highlighter(container) * * // 自定义配置 * const highlighter2 = new Highlighter(container, { * highlightTag: 'span', * highlightClass: 'search-highlight', * activeClass: 'current-match', * skipTags: ['SCRIPT', 'STYLE', 'CODE'], * scrollOptions: { behavior: 'auto', block: 'nearest' }, * smartScroll: false, // 禁用智能滚动 * scrollPadding: 30 // 设置较小的视口内边距 * }) * * // 带回调的配置 * const highlighter3 = new Highlighter(container, { * highlightClass: 'result' * }, { * onHighlightApplied: (count) => console.log(`找到 ${count} 个匹配项`), * onNavigate: (index, total) => console.log(`${index + 1}/${total}`) * }) * ``` */ constructor(targetNode: HTMLElement, config?: HighlighterConfig, callbacks?: HighlightCallbacks); /** * 准备应用正则表达式高亮的内部方法 * * @param regex - 正则表达式 * @returns 准备好的数据或 null(如果正则表达式无效) */ private _prepareApplyRegex; /** * 准备高亮应用的前置工作 * @internal */ private _prepareApply; /** * 完成正则表达式高亮应用的后续工作 * @internal */ private _finalizeApplyRegex; /** * 完成高亮应用的后续工作 * @internal */ private _finalizeApply; /** * 应用高亮到指定关键词(异步版本) * * 在目标元素中搜索并高亮显示指定的关键词。会自动清理之前的高亮, * 并为新的匹配项设置高亮样式。完成后会自动定位到第一个匹配项。 * 异步版本支持性能优化,适合处理大文档。 * * @param keywords - 要高亮的关键词,可以是单个字符串或字符串数组,空字符串或仅包含空白字符的字符串将被忽略 * @param options - 高亮选项配置 * @returns 匹配项的数量 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * * // 基本高亮(单个关键词) * const count1 = await highlighter.apply('JavaScript') * * // 多个关键词高亮 * const count2 = await highlighter.apply(['JavaScript', 'TypeScript', 'React']) * * // 区分大小写的高亮 * const count3 = await highlighter.apply(['JavaScript', 'API'], { caseSensitive: true }) * * // 只匹配完整单词 * const count4 = await highlighter.apply(['script', 'code'], { wholeWord: true }) * * // 组合选项 * const count5 = await highlighter.apply(['API', 'SDK'], { * caseSensitive: true, * wholeWord: true * }) * ``` * * @remarks * - 该方法会跳过配置中指定的标签内的文本 * - 不会在已经高亮的元素内进行嵌套高亮 * - 使用TreeWalker遍历文本节点以确保性能 * - 关键词中的正则表达式特殊字符会被自动转义 * - 支持性能优化,在处理大量节点时会分批处理避免阻塞UI * - 多个关键词会被组合成一个正则表达式进行匹配 */ apply(keywords: string | string[], options?: HighlightOptions): Promise; /** * 应用高亮到指定关键词(同步版本) * * 在目标元素中搜索并高亮显示指定的关键词。会自动清理之前的高亮, * 并为新的匹配项设置高亮样式。完成后会自动定位到第一个匹配项。 * 同步版本不包含性能优化,适合处理小到中等大小的文档。 * * @param keywords - 要高亮的关键词,可以是单个字符串或字符串数组,空字符串或仅包含空白字符的字符串将被忽略 * @param options - 高亮选项配置 * @returns 匹配项的数量 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * * // 基本高亮(单个关键词) * const count1 = highlighter.applySync('JavaScript') * * // 多个关键词高亮 * const count2 = highlighter.applySync(['JavaScript', 'TypeScript', 'React']) * * // 区分大小写的高亮 * const count3 = highlighter.applySync(['JavaScript', 'API'], { caseSensitive: true }) * * // 只匹配完整单词 * const count4 = highlighter.applySync(['script', 'code'], { wholeWord: true }) * * // 组合选项 * const count5 = highlighter.applySync(['API', 'SDK'], { * caseSensitive: true, * wholeWord: true * }) * ``` * * @remarks * - 该方法会跳过配置中指定的标签内的文本 * - 不会在已经高亮的元素内进行嵌套高亮 * - 使用TreeWalker遍历文本节点以确保性能 * - 关键词中的正则表达式特殊字符会被自动转义 * - 同步执行,不会分批处理,适合小到中等大小的文档 * - 多个关键词会被组合成一个正则表达式进行匹配 */ applySync(keywords: string | string[], options?: HighlightOptions): number; /** * 使用自定义正则表达式应用高亮(异步版本) * * 使用提供的正则表达式在目标元素中搜索并高亮显示匹配的文本。 * 会自动清理之前的高亮,并为新的匹配项设置高亮样式。 * 异步版本支持性能优化,适合处理大文档。 * * @param regex - 用于匹配的正则表达式,必须包含全局标志 'g' * @returns 匹配项的数量 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * * // 高亮所有邮箱地址 * const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g * const count1 = await highlighter.applyRegex(emailRegex) * * // 高亮日期格式 YYYY-MM-DD * const dateRegex = /\d{4}-\d{2}-\d{2}/g * const count2 = await highlighter.applyRegex(dateRegex) * * // 高亮 "Chapter" 或 "Section" 后跟数字 * const chapterRegex = /(Chapter|Section)\s+\d+/gi * const count3 = await highlighter.applyRegex(chapterRegex) * ``` * * @throws 如果传入的正则表达式没有 'g' 标志,则会抛出错误 * * @remarks * - 该方法会跳过配置中指定的标签内的文本 * - 不会在已经高亮的元素内进行嵌套高亮 * - 使用TreeWalker遍历文本节点以确保性能 * - 支持性能优化,在处理大量节点时会分批处理避免阻塞UI * - 正则表达式必须包含全局标志 'g' 以确保能匹配所有实例 */ applyRegex(regex: RegExp): Promise; /** * 使用自定义正则表达式应用高亮(同步版本) * * 使用提供的正则表达式在目标元素中搜索并高亮显示匹配的文本。 * 会自动清理之前的高亮,并为新的匹配项设置高亮样式。 * 同步版本不包含性能优化,适合处理小到中等大小的文档。 * * @param regex - 用于匹配的正则表达式,必须包含全局标志 'g' * @returns 匹配项的数量 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * * // 高亮所有邮箱地址 * const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g * const count1 = highlighter.applyRegexSync(emailRegex) * * // 高亮日期格式 YYYY-MM-DD * const dateRegex = /\d{4}-\d{2}-\d{2}/g * const count2 = highlighter.applyRegexSync(dateRegex) * ``` * * @throws 如果传入的正则表达式没有 'g' 标志,则会抛出错误 * * @remarks * - 该方法会跳过配置中指定的标签内的文本 * - 不会在已经高亮的元素内进行嵌套高亮 * - 使用TreeWalker遍历文本节点以确保性能 * - 同步执行,不会分批处理,适合小到中等大小的文档 * - 正则表达式必须包含全局标志 'g' 以确保能匹配所有实例 */ applyRegexSync(regex: RegExp): number; /** * 移除所有高亮 * * 清除目标元素中的所有高亮标记,将高亮的文本恢复为普通文本。 * 同时重置内部状态,包括高亮元素列表和当前索引。 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply('JavaScript') * // ... 一些操作后 * highlighter.remove() // 清除所有高亮 * ``` */ remove(): void; /** * 导航到下一个或上一个高亮项 * * 根据指定的方向(1或-1)导航到下一个或上一个高亮项。 * 会自动更新当前索引并调用回调函数。 * * @param direction - 导航方向,1表示下一个,-1表示上一个 * @returns 是否成功导航 */ private _navigate; /** * 跳转到下一个高亮项 * * 将当前激活的高亮项切换到下一个匹配项。如果当前是最后一个, * 则循环到第一个。会自动滚动到目标元素并更新激活状态。 * * @returns 是否成功跳转 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply('JavaScript') * const success = highlighter.next() // 跳转到下一个匹配项 * ``` */ next(): boolean; /** * 跳转到上一个高亮项 * * 将当前激活的高亮项切换到上一个匹配项。如果当前是第一个, * 则循环到最后一个。会自动滚动到目标元素并更新激活状态。 * * @returns 是否成功跳转 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply('JavaScript') * const success = highlighter.previous() // 跳转到上一个匹配项 * ``` */ previous(): boolean; /** * 跳转到指定索引的高亮项 * * 直接跳转到指定索引位置的高亮项。索引从0开始计算。 * * @param index - 目标索引(从0开始) * @returns 是否成功跳转 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply('JavaScript') * const success = highlighter.jumpTo(5) // 跳转到第6个匹配项 * ``` */ jumpTo(index: number): boolean; /** * 获取匹配总数 * * 返回当前高亮关键词的匹配项总数。 * * @returns 匹配项的总数 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply('JavaScript') * console.log(`找到 ${highlighter.getMatchCount()} 个匹配项`) * ``` */ getMatchCount(): number; /** * 获取当前激活项的索引 * * 返回当前激活的高亮项在所有匹配项中的索引位置(从0开始)。 * 如果没有匹配项,返回-1。 * * @returns 当前激活项的索引,如果没有匹配项则返回-1 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply('JavaScript') * console.log(`当前是第 ${highlighter.getCurrentIndex() + 1} 个匹配项`) * ``` */ getCurrentIndex(): number; /** * 获取当前高亮的关键词 * * @returns 当前高亮的关键词数组,如果没有高亮则返回空数组 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply(['JavaScript', 'TypeScript']) * console.log(`当前高亮关键词: ${highlighter.getCurrentKeywords().join(', ')}`) * ``` */ getCurrentKeywords(): string[]; /** * 获取当前高亮的模式 * * @returns 当前高亮的模式,可能是关键词数组或正则表达式 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * * // 使用关键词高亮 * await highlighter.apply(['JavaScript', 'tutorial']) * console.log(highlighter.getCurrentPattern()) // ['JavaScript', 'tutorial'] * * // 使用正则表达式高亮 * const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g * await highlighter.applyRegex(emailRegex) * console.log(highlighter.getCurrentPattern()) // RegExp object * ``` */ getCurrentPattern(): string[] | RegExp; /** * 获取当前高亮的关键词(兼容性方法) * * @returns 当前高亮的关键词字符串,多个关键词用逗号分隔,如果没有高亮则返回空字符串 * @deprecated 建议使用 getCurrentKeywords() 方法 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply(['JavaScript', 'TypeScript']) * console.log(`当前高亮关键词: ${highlighter.getCurrentKeyword()}`) * ``` */ getCurrentKeyword(): string; /** * 获取当前激活的高亮元素 * * @returns 当前激活的高亮元素,如果没有则返回null * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply('JavaScript') * const activeElement = highlighter.getCurrentElement() * if (activeElement) { * console.log('当前激活元素的文本:', activeElement.textContent) * } * ``` */ getCurrentElement(): HTMLElement | null; /** * 获取所有高亮元素 * * @returns 所有高亮元素的数组副本 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.apply('JavaScript') * const allHighlights = highlighter.getAllHighlights() * console.log(`总共有 ${allHighlights.length} 个高亮元素`) * ``` */ getAllHighlights(): HTMLElement[]; /** * 更新配置 * * 动态更新高亮器的配置。注意:某些配置更改可能需要重新应用高亮才能生效。 * * @param newConfig - 新的配置选项 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.updateConfig({ * highlightClass: 'new-highlight-class', * scrollOptions: { behavior: 'auto' } * }) * ``` */ updateConfig(newConfig: Partial): void; /** * 更新回调函数 * * 动态更新事件回调函数。 * * @param newCallbacks - 新的回调函数 * * @example * ```typescript * const highlighter = new Highlighter(document.body) * highlighter.updateCallbacks({ * onNavigate: (index, total) => { * console.log(`导航到: ${index + 1}/${total}`) * } * }) * ``` */ updateCallbacks(newCallbacks: Partial): void; /** * 检查元素是否在视口的舒适可见区域内 * @param el - 要检查的HTML元素 * @returns 如果元素在视口内则返回true,否则返回false * @internal */ private _isElementInViewport; /** * 创建包含高亮标记的文档片段 * * 根据正则表达式匹配结果,将文本分割并创建包含高亮元素的文档片段。 * 匹配的部分会被包装在指定的高亮标签中,非匹配部分保持为普通文本节点。 * * @param text - 要处理的文本内容 * @param regex - 用于匹配的正则表达式 * @returns 包含高亮标记的文档片段 * * @internal */ private createHighlightedFragment; /** * 设置当前激活的高亮项 * * 移除所有高亮元素的激活状态,然后为当前索引对应的元素添加激活样式。 * 如果启用了智能滚动,只有当目标元素不在视口内时才会触发滚动。 * * @internal */ private setActiveHighlight; /** * 私有核心查找逻辑 * 查找下一个或上一个在视口外的元素的索引。 * @param direction - 查找方向, 1 为向前, -1 为向后 * @returns 找到的元素的索引,如果没找到则返回 -1 * @internal */ private _findOffscreenIndex; /** * 查找下一个在视口外的匹配项的索引 * @returns 找到的元素的索引,如果所有元素都在视口内则返回 -1 */ findNextOffscreenIndex(): number; /** * 查找上一个在视口外的匹配项的索引 * @returns 找到的元素的索引,如果所有元素都在视口内则返回 -1 */ findPreviousOffscreenIndex(): number; /** * 跳转到下一个在视口外的匹配项 * * 如果找到了屏幕外的匹配项,则直接跳转到那里。 * 如果所有匹配项都在视口内,则行为与 next() 相同,以确保总有反馈。 * @returns 是否成功执行了跳转或导航操作 */ jumpToNextOffscreen(): boolean; /** * 跳转到上一个在视口外的匹配项 * * 如果找到了屏幕外的匹配项,则直接跳转到那里。 * 如果所有匹配项都在视口内,则行为与 previous() 相同,以确保总有反馈。 * @returns 是否成功执行了跳转或导航操作 */ jumpToPreviousOffscreen(): boolean; /** * 销毁高亮器实例 * * 清理所有内部状态、引用和事件监听器(如果有)。 * 在组件卸载时调用此方法以防止内存泄漏。 */ destroy(): void; } //#endregion export { Highlighter };