效果如下图:
APIs Highlight 参数 说明 类型 默认值 text 文本 string undefined patterns 需要高亮的文本内容 string[] [] autoEscape 自动转义。默认情况下,patterns中的元素会被转化为正则表达式进行匹配,这个过程中需要进行自动转义,正则表达式最终匹配的是元素的字面内容,例如\(匹配的就是\(。如果你需要Highlight组件去匹配使用patterns中元素本身构造的正则表达式,例如\(匹配的是(,则可以设为false。如果你看不懂这些,不要改这个设置。 boolean true caseSensitive 区分大小写 boolean false highlightTag 高亮内容的HTML元素类型 string ‘mark’ highlightClass 高亮内容的类名 string undefined highlightStyle 高亮内容的样式 CSSProperties {}
创建高亮文本组件Highlight.vue < script setup lang= "ts" > import { computed, h} from 'vue' import type { CSSProperties} from 'vue' export interface Props { text? : string // 文本 patterns? : string [ ] // 需要高亮的文本内容 autoEscape? : boolean // 自动转义。默认情况下,patterns 中的元素会被转化为正则表达式进行匹配,这个过程中需要进行自动转义,正则表达式最终匹配的是元素的字面内容,例如 \( 匹配的就是 \(。如果你需要 n-highlight 组件去匹配使用 patterns 中元素本身构造的正则表达式,例如 \( 匹配的是 (,则可以设为 false。如果你看不懂这些,不要改这个设置。 caseSensitive? : boolean // 区分大小写 highlightTag? : string // 高亮内容的 HTML 元素类型 highlightClass? : string // 高亮内容的类名 highlightStyle? : CSSProperties// 高亮内容的样式 } const props= withDefaults ( defineProps < Props> ( ) , { text: undefined , patterns : ( ) => [ ] , autoEscape: true , caseSensitive: false , highlightTag: 'mark' , highlightClass: undefined , highlightStyle : ( ) => ( { } ) } ) const textOrVnodeChildren= computed ( ( ) => { if ( props. patterns. length=== 0 || ! props. text) { return [ props. text] } else { const patternStr= props. patterns. map ( ( word) => ( props. autoEscape? escapeRegExp ( word) : word) ) . join ( '|' ) const regex= new RegExp ( ` ( ${ patternStr} ) ` , props. caseSensitive? 'g' : 'gi' ) const splitItems= splitAndMarkByRegex ( props. text, regex) return splitItems. map ( ( item: { text: string ; isMatch: boolean } ) => { if ( item. isMatch) { return h ( props. highlightTag, { class : [ 'highlight-mark' , props. highlightClass] , style: props. highlightStyle} , item. text) } return item. text} ) } } ) function escapeRegExp ( text: string ) : string { return text. replace ( / [.*+?^${}()|[\]\\] / g , '\\$&' ) } function splitAndMarkByRegex ( str: string , regex: RegExp) : Array < { text: string ; isMatch: boolean } > { const result= [ ] let lastIndex= 0 let match// 在一个指定字符串中执行一个搜索匹配,返回一个结果数组或 null while ( ( match= regex. exec ( str) ) !== null ) { if ( match. index> lastIndex) { result. push ( { text: str. slice ( lastIndex, match. index) , isMatch: false } ) } result. push ( { text: match[ 0 ] , isMatch: true } ) lastIndex= regex. lastIndex// 针对字符串中所有可能的匹配项测试正则表达式,还是仅针对第一个匹配项 if ( ! regex. global) { break } } if ( lastIndex< str. length) { result. push ( { text: str. slice ( lastIndex) , isMatch: false } ) } return result} < / script> < template> < spanclass = "highlight-wrap" > < template v- for = "(textOrVnode, index) in textOrVnodeChildren" : key= "index" > < template v- if = "typeof textOrVnode === 'string'" > { { textOrVnode} } < / template> < component v- else : is = "textOrVnode" / > < / template> < / span> < / template> 在要使用的页面引入 < script setup lang= "ts" > import Highlightfrom './Highlight.vue' import { ref} from 'vue' const text= ref ( 'Vue Amazing UI 是一个 Vue3 的组件库,主题可调,全量使用 TypeScript 和 SFC,支持 tree shaking,有点意思' ) const patterns= ref ( [ 'Vue Amazing UI' , 'Vue3' , 'TypeScript' , 'SFC' , 'tree shaking' ] ) < / script> < template> < div> < h1> { { $route. name} } { { $route. meta. title} } < / h1> < h2class = "mt30 mb10" > 基本使用< / h2> < Highlight: text= "text" : patterns= "patterns" / > < h2class = "mt30 mb10" > 样式< / h2> < Highlight text= "Vue Amazing UI 全量使用 TypeScript 编写,和你的 TypeScript 项目无缝衔接" : patterns= "['Vue Amazing UI', 'TypeScript']" : highlight- style= "{ padding: '0 6px' , borderRadius: '4px' , display: 'inline-block' , color: '#fff' , background: '#1677ff' , transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)' } "/ > < h2class = "mt30 mb10" > 区分大小写< / h2> < Highlight text= "Vue Amazing UI 全量使用 TypeScript 编写,和你的 TypeScript 项目无缝衔接" : patterns= "['Vue Amazing UI', 'typeScript']" case - sensitive/ > < h2class = "mt30 mb10" > 高亮标签< / h2> < Highlight: text= "text" : patterns= "patterns" highlight- tag= "span" : highlight- style= "{ fontWeight: '500', color: '#ff6900', textDecoration: 'underline' }" / > < / div> < / template>