vue3 + TS 封装轻量级关键词高亮组件

799 阅读3分钟

1. 简洁轻量

组件代码简洁明了,没有复杂的逻辑和冗余代码,使其非常轻量级。整个组件只有约 80 行代码,但功能完整,这意味着:

  • 加载速度快
  • 运行时消耗资源少
  • 易于理解和维护

2. 类型安全

使用 TypeScript 接口定义了明确的 Props 类型,提供了:

  • 类型检查
  • 清晰的属性文档(包括默认值注释)
  • 减少运行时错误

3. 高度可配置

尽管代码简洁,但提供了丰富的配置选项:

  • 自定义高亮颜色
  • 自定义背景色
  • 控制是否使用粗体
  • 支持区分大小写匹配
  • 支持使用自定义 CSS 类

4. 性能优化

组件使用了 Vue 的计算属性进行优化:

  • highlightStylehighlightedText 都是计算属性,只在依赖变化时重新计算
  • 避免了不必要的重复计算
  • 使用正则表达式一次性替换所有匹配项,而不是多次操作 DOM

5. 安全性考虑

组件包含安全处理:

  • 使用 escapeRegExp 函数转义正则表达式特殊字符,防止用户输入的关键词破坏正则表达式
  • 处理空文本和空关键词的边缘情况
  • 使用 v-html 指令安全地渲染 HTML 内容

6. 灵活的样式选项

提供了两种设置高亮样式的方式:

  • 内联样式:通过 highlightStyle 计算属性动态生成
  • CSS 类:通过 customClass 属性支持外部定义的样式类

7. 易于集成

组件设计使其易于集成到各种场景:

  • 可以用于搜索结果高亮
  • 可以用于文档内容关键词突出显示
  • 可以用于教学内容中重点标记

8. 良好的默认值

组件为所有可选属性提供了合理的默认值:

  • 默认高亮颜色为红色 (#f56c6c)
  • 默认背景色为淡红色 (rgba(245, 108, 108, 0.1))
  • 默认使用粗体
  • 默认不区分大小写

9. 响应式设计

组件充分利用了 Vue 3 的响应式系统:

  • textkeyword 属性变化时,高亮效果会自动更新
  • 当样式相关属性变化时,高亮样式会自动更新

10. 代码可读性高

代码结构清晰,变量命名直观,注释完善,使得:

  • 新开发者容易理解
  • 便于后续维护和扩展
  • 可作为学习 Vue 3 组件开发的良好示例

使用示例

新建组件 components/HighlightText/index.vue


<template>
  <span class="text" v-html="highlightedText"></span>
</template>

<script lang="ts" setup>
import { computed } from 'vue'

interface Props {
  /**
   * 要高亮的文本内容
   */
  text: string

  /**
   * 要高亮的关键词
   */
  keyword: string

  /**
   * 高亮的颜色
   * @default "#f56c6c"
   */
  highlightColor?: string

  /**
   * 高亮的背景色
   * @default "rgba(245, 108, 108, 0.1)"
   */
  highlightBgColor?: string

  /**
   * 是否使用粗体
   * @default true
   */
  bold?: boolean

  /**
   * 是否区分大小写
   * @default false
   */
  caseSensitive?: boolean

  /**
   * 自定义高亮的CSS类名
   */
  customClass?: string
}

const props = withDefaults(defineProps<Props>(), {
  highlightColor: '#f56c6c',
  highlightBgColor: 'rgba(245, 108, 108, 0.1)',
  bold: true,
  caseSensitive: false,
  customClass: ''
})

// 生成高亮样式
const highlightStyle = computed(() => {
  const styles = [
    `color: ${props.highlightColor}`,
    `background-color: ${props.highlightBgColor}`,
    'padding: 0 2px',
    'border-radius: 2px'
  ]

  if (props.bold) {
    styles.push('font-weight: bold')
  }

  return styles.join(';')
})

// 生成高亮的HTML
const highlightedText = computed(() => {
  if (!props.text || !props.keyword) {
    return props.text || ''
  }
  // 简单文本替换
  const flags = props.caseSensitive ? 'g' : 'gi'
  const regex = new RegExp(`(${escapeRegExp(props.keyword)})`, flags)

  if (props.customClass) {
    return props.text.replace(regex, `<span class="${props.customClass}">$1</span>`)
  } else {
    return props.text.replace(regex, `<span style="${highlightStyle.value}">$1</span>`)
  }
})

// 转义正则表达式特殊字符
function escapeRegExp(string: string): string {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
</script>

<style lang="less" scoped>
.text {
  font-size: 14px;
  color: #464646;
}
</style>

新建TS components/index.ts

// 引入项目中的全局组件
import HighlightText from './HighlightText/index.vue'
// 全局对象
const allGlobalComponent = { HighlightText }

// 对外暴露插件对象
export default {
  install(app) {
    // 注册项目全部的全局组件
    Object.keys(allGlobalComponent).forEach((key) => {
      // 注册为全局组件
      app.component(key, allGlobalComponent[key])
    })
  }
}

main.ts

// 导入插件对象
import globalComponents from './components/index'

//注册
app.use(globalComponents)

全局使用

<!-- 基本用法 -->
<HighlightText text="这是一段示例文本" keyword="示例" />

<!-- 自定义样式 -->
<HighlightText 
  text="这是一个重要提示" 
  keyword="重要" 
  highlight-color="#1677ff"
  highlight-bg-color="rgba(22, 119, 255, 0.1)"
/>

<!-- 使用自定义类 去掉父组件的scoped  -->
<HighlightText 
  text="使用自定义CSS类" 
  keyword="CSS" 
  custom-class="my-highlight"
/>