VUE 实现内容搜索并高亮显示

本文介绍了一种实现思路,通过正则表达式实现检索内容的实时高亮和定位,用户可以方便地切换上下文,便于快速查找和理解关键信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求背景:

1.输入的检索内容

2.显示共匹配多少个检索内容,当前显示的位置是在第几个匹配的检索内容

3.点击上一个图标可以找到上一条的匹配内容所在位置

4.点击下一个图标可以找到下一条的匹配内容所在位置

5.检索内容修改后,点击检索图标可对内容进行匹配检修

实现思路:

1.根据检索的关键词把文章中所有匹配的内容替换成<span class='highlight_Keyword'>关键词<span>

2.使用正则表达式查找所有带‘highlight_Keyword’的索引位置

3.在当前查找的索引替换成当前高亮的样式 “ highlight_Keyword highlight_yellow” 

4.在css中设置好对应的样式就OK啦

先展示效果图:

用到的相关正则:

// 清除所有span标签
var reg1 = new RegExp('</?span.*?>', 'gi') //g 全局搜索 i表示不区分大小写
this.contextHtml = this.contextHtml.replace(reg1, '')

//搜索关键词,并返回所在位置(索引)
var rStr = new RegExp(value, 'gi') //i表示不区分大小写,g表示全局搜索
      var arr = sText.match(rStr)
      var a = -1
      sText = sText.replace(rStr, function() {
        a++
        return '<span class="highlight_Keyword">' + arr[a] + '</span>'
      })

 放在component路径下作为组件使用,可以直接使用

<template>
  <div class="keywords-search">
    <div class="keywords-search-left">
      <el-input
        v-model="searchNodeInput"
        placeholder="请输入节点名称"
        clearable
        @keyup.down.native="inputDown"
        @keyup.up.native="inputUp"
        @keyup.enter.native="inputDown"
      />

      <div>
        <span class="m-r-10">{{ nowNum }}/{{ totalNum }}</span>
        <a
          class="setting-secondary m-r-10"
          href="javascript:void(0)"
          :disabled="inputUpDisable"
          @click="inputUp"
        >
          <i class="fa fa-caret-up" />
        </a>
        <a
          class="setting-secondary m-r-10"
          href="javascript:void(0)"
          :disabled="inputDownDisable"
          @click="inputDown"
        >
          <i class="fa fa-caret-down" />
        </a>
        <a
          class="setting-primary"
          href="javascript:void(0)"
          @click="changeSearchNodeInput"
        >
          <i class="fa fa-search" />
        </a>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'KeywordSearch',
  props: {
    searchNodeInput: { type: String }, // 父级输入框的值
    context: { type: String } // 父级要搜索的内容
  },
  data() {
    return {
      contextHtml: null,
      nowNum: 0,
      totalNum: 0,
      currentLabel: '',
      currentNodeIndex: 0,
      inputUpDisable: false,
      inputDownDisable: false,
      nodeSearchArr: []
    }
  },
  watch: {
    searchNodeInput(newVal, oldVal) {
      if (oldVal) {
        console.log('oldVal:', oldVal)
        console.log('newVal:', newVal)

        // const rStr = '<span class="highlight_Keyword">' + oldVal + '<\/span>'
        // this.contextHtml = this.contextHtml.replaceAll(rStr, oldVal)
      }
      // 因为性能问题,暂时不使用值改变就搜索
      // this.changeSearchNodeInput()
    }
  },
  methods: {
    // 上一个
    inputUp() {
      if (this.totalNum >= 1) {
        this.inputUpDisable = false
        if (this.currentNodeIndex === 0) {
          this.currentNodeIndex = Number(this.totalNum) - 1
          this.nowNum = String(this.currentNodeIndex + 1)
        } else {
          this.currentNodeIndex = this.currentNodeIndex - 1
          this.nowNum = String(this.currentNodeIndex + 1)
        }
        this.findKeyword(this.currentNodeIndex)
      } else {
        // 这里向上的按钮要disable掉
        this.inputUpDisable = true
      }
    },
    // 下一个
    inputDown() {
      if (this.totalNum >= 1) {
        this.inputDownDisable = false
        if (this.currentNodeIndex === this.totalNum - 1) {
          this.currentNodeIndex = 0
          this.nowNum = String(this.currentNodeIndex + 1)
        } else {
          this.currentNodeIndex = this.currentNodeIndex + 1
          this.nowNum = String(this.currentNodeIndex + 1)
        }
        this.findKeyword(this.currentNodeIndex)
      } else {
        // 这里向下的按钮要disable掉
        this.inputDownDisable = true
      }
    },
    // 改变搜索框中的值
    changeSearchNodeInput() {
      if (!this.searchNodeInput) {
        return
      }
      debugger
      if (!this.contextHtml) {
        this.contextHtml = this.context
      } else {
        // 清除所有span标签
        var reg1 = new RegExp('</?span.*?>', 'gi') // 匹配传入的搜索值不区分大小写 i表示不区分大小写,g表示全局搜索
        this.contextHtml = this.contextHtml.replace(reg1, '')
      }
      let sText = this.contextHtml
      const value = this.searchNodeInput
      var rStr = new RegExp(value, 'gi') // 匹配传入的搜索值不区分大小写 i表示不区分大小写,g表示全局搜索
      var arr = sText.match(rStr)
      var a = -1
      sText = sText.replace(rStr, function() {
        a++
        return '<span class="highlight_Keyword">' + arr[a] + '</span>'
      })

      this.nodeSearchArr = this.searchSubStr(sText, 'highlight_Keyword')
      this.totalNum = this.nodeSearchArr.length
      if (this.totalNum >= 1) {
        this.nowNum = '1'
        this.currentNodeIndex = 0
        this.inputUpDisable = false
        this.inputDownDisable = false
      } else {
        this.nowNum = '0'
        this.inputUpDisable = true
        this.inputDownDisable = true
        this.currentNodeIndex = -1
      }
      this.contextHtml = sText
      this.findKeyword(this.currentNodeIndex)
    },
    findKeyword(index) {
      if (index > -1) {
        // 清空当前高亮
        this.clearCurrentStyle()

        this.contextHtml = this.replaceStr(
          this.contextHtml,
          this.nodeSearchArr[index],
          ' highlight_yellow'
        )
      }
      this.$emit('highlightKeyword', {
        context: this.contextHtml,
        keyword: this.searchNodeInput
      })
    },
    // 查找所有'highlight_Keyword'位置
    searchSubStr(str, findStr) {
      let res
      const list = []
      const reg = new RegExp(findStr, 'gi')
      while ((res = reg.exec(str))) {
        // 把highlight_Keyword结束位置加到数组中
        list.push(res.index + findStr.length)
      }
      console.log(list) // [8, 11, 29, 37, 51, 64]
      return list
    },
    // 指定位置插入字符串
    replaceStr(str, index, char) {
      return str.substring(0, index) + char + str.substring(index)
    },
    // 清空当前高亮
    clearCurrentStyle() {
      this.contextHtml = this.contextHtml.replaceAll(' highlight_yellow', '')
    }
  }
}
</script>

<think>嗯,用户问的是如何在Vue实现PDF文件内的关键词搜索高亮显示。首先,我需要回想一下Vue中常用的PDF处理库。之前记得pdf.js是常用的,因为它可以在浏览器中直接渲染PDF,不需要后端处理。然后,用户提到的高亮功能,可能需要结合搜索功能来实现。 接下来,我应该检查用户提供的引用内容。引用[3]和[4]提到了PDF.js如何实现多个关键词的高亮显示。看来PDF.js本身有搜索功能,可以通过事件触发搜索,然后高亮结果。但可能需要自定义一些部分,比如处理多个关键词或者样式调整。 然后,用户的需求可能涉及到如何将PDF.js集成到Vue项目中。可能需要使用vue-pdf这个库,它是对pdf.js的封装,方便在Vue中使用。但需要确认vue-pdf是否支持搜索和高亮功能。如果vue-pdf不支持,可能需要直接使用pdf.js,或者结合其他插件。 另外,引用[1]和[2]讲的是Vue中普通文本的高亮,通常使用v-html和正则替换。但PDF的高亮不同,因为PDF是渲染在canvas上的,无法直接操作DOM元素。所以需要利用pdf.js自带的搜索功能,或者通过获取文本层数据,手动添加高亮元素。 可能还需要分步骤来:加载PDF、监听搜索事件、高亮匹配的文本。需要用到PDFViewerApplication这个对象的事件,比如'find'事件,传递关键词和参数。但要注意PDF.js的版本,不同版本可能有差异,比如引用[4]提到在1202行附近修改代码,可能需要自定义构建pdf.js。 此外,如果用户需要多个关键词同时高亮,可能需要循环调用搜索方法,或者修改pdf.js的源码来支持多关键词。这可能会比较复杂,需要处理多个高亮区域,确保它们正确显示。 最后,总结可能的解决方案:使用pdf.js或vue-pdf加载PDF,调用其内置搜索方法,然后通过自定义样式或事件处理来实现高亮。可能需要参考引用中的示例代码,比如调用PDFViewerApplication.eventBus.dispatch来触发搜索设置highlightAll为true。 需要注意的潜在问题包括跨域问题,PDF文件需要正确配置CORS;样式问题,可能需要调整高亮颜色和位置;以及性能问题,处理大文件时可能会卡顿。因此,建议使用分页加载和优化搜索逻辑。</think>### Vue实现PDF关键词搜索高亮的解决方案 在Vue实现PDF文件内关键词搜索高亮显示效果,主要通过**PDF.js库**结合自定义搜索逻辑实现。以下是具体实现步骤和技术要点: --- #### 一、核心实现方案 1. **使用PDF.js库** - 核心库:采用Mozilla开源的$pdf.js$实现PDF解析与渲染[^3] - Vue集成:推荐使用$vue-pdf$封装库或原生集成 ```bash npm install pdfjs-dist vue-pdf ``` 2. **搜索高亮原理** ```mermaid graph TD A[加载PDF文件] --> B[获取文本图层] B --> C[执行关键词搜索] C --> D[定位匹配位置] D --> E[添加高亮蒙层] ``` --- #### 二、具体实现步骤 1. **基础PDF显示** ```vue <template> <div ref="pdfContainer"></div> </template> <script> import * as pdfjsLib from 'pdfjs-dist/build/pdf' import 'pdfjs-dist/web/pdf_viewer.css' export default { methods: { async loadPDF(url) { const container = this.$refs.pdfContainer const pdf = await pdfjsLib.getDocument(url).promise const page = await pdf.getPage(1) // 渲染页面到canvas } } } </script> ``` 2. **关键词搜索实现** ```javascript // 触发搜索事件 PDFViewerApplication.eventBus.dispatch('find', { query: '关键词', caseSensitive: false, highlightAll: true, findPrevious: true })[^3] ``` 3. **自定义高亮样式** ```css .textLayer .highlight { background-color: rgba(255,0,0,0.3); border-radius: 3px; } ``` --- #### 三、进阶优化方案 1. **多关键词高亮** ```javascript // 循环处理多个关键词 ['vue', 'pdf'].forEach(keyword => { PDFViewerApplication.findController.executeCommand('find', { query: keyword, highlightAll: true })[^4] }) ``` 2. **跨页面搜索** ```javascript const totalPages = PDFViewerApplication.pdfDocument.numPages; for(let i=1; i<=totalPages; i++) { const page = await PDFViewerApplication.pdfDocument.getPage(i) const textContent = await page.getTextContent() // 文本匹配处理 } ``` 3. **性能优化** - 使用$web worker$加载PDF文件 - 实现分页加载机制 - 添加搜索节流函数 --- #### 四、推荐工具库 | 工具库 | 特点 | 文档链接 | |--------|------|----------| | pdfjs-dist | 官方标准库 | [mozilla.github.io/pdf.js](https://mozilla.github.io/pdf.js/) | | vue-pdf | Vue专用封装 | [npmjs.com/package/vue-pdf](https://www.npmjs.com/package/vue-pdf) | | pdf-lib | 动态修改PDF | [pdf-lib.js.org](https://pdf-lib.js.org/) | ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值