需求背景:

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>

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐