React实现文字高亮

在项目开发中遇到一个头疼的问题,就是在搜索数据后渲染的同时把框出来的部分命中搜索关键词经行高亮,如果是普通的字符串高亮很简单,调用_match方法就行了当然,可以直接返回jsx(代码中被注释的部分),但是如图,不是纯文本,里面掺杂中表情的img标签,也有可能是提交的代码块,比如:

dal;jksdajk[闭嘴][闭嘴][大哭][再见][亲亲][示爱][哈欠]dajalkjg @cp1 @cp2

其中img标签是不允许被破坏的,所以就需要对文本进行抽取其中的html标签部分后在重新生成新的高亮后的字符串或jsx,在react中通过 dangerouslySetInnerHTML经行解析,最终实现效果如下图

React实现文字高亮_第1张图片

  const _match = (keyword, content) => {
    const reg = new RegExp(keyword.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'), 'ig')

    const splitIconTypes = content.split(reg)
    const match = content.match(reg)
    let matchStr = (match || [])
      .map((_, index) => {
        return `${splitIconTypes[index]}${match[index]}`
      })
      .join('')
    return `${matchStr}${splitIconTypes[splitIconTypes.length - 1] || ''}`
    // return (
    //   <>
    //     {
    //       (match || [])
    //       .map((_, index) => {
    //         return 
    //           
    //           ${match[index]}
    //         
    //       })
    //     }
    //     ${splitIconTypes[splitIconTypes.length - 1] || ''}
    //   
    // )
  }

  const _renderHighlight = text => {
    if (keyword && text) {
      let matches = text.match(/<[^>]*>/gi)
      if (matches) {
        let newText = []
        for (let i = 0; i < matches.length; i++) {
          let temp = matches[i]
          if (i === 0) {
            let content = text.split(temp)[0]
            if (content) newText.push(_match(keyword, content))
            newText.push(temp)
          } else if (i === matches.length - 1) {
            let prev = matches[i - 1]
            let content = text.split(temp)[0].split(prev)[1]
            if (content) newText.push(_match(keyword, content))
            newText.push(temp)

            content = text.split(temp)[1]
            if (content) newText.push(_match(keyword, content))
          } else {
            let prev = matches[i - 1]
            let content = text.split(temp)[0].split(prev)[1]
            if (content) newText.push(_match(keyword, content))
            newText.push(temp)
          }
        }
        return newText.join('')
      } else {
        return _match(keyword, text)
      }
    } else {
      return text
    }
  }

text = "周期计划1011\r
客户标签:测试标签2 测试标签7 测试标签6 测试标签4 测试标签3 测试标签9 测试标签10 测试标签5 测试标签8 测试标签\r
抵达:  14:05 距离客户位置小于500.0米\r
离开:  14:05 距离客户位置小于500.0米\r
在店时长:0分钟\r
拜访工作:1次7110新增表单"

经过测试上面的_renderHighlight 方法有个bug,改良后的方法

  const _renderHighlight = text => {
    if (keyword && text) {
      // 匹配html标签
      let matches = text.match(/<[^>]*>/gi)
      if (matches) {
        let newText = []
        let lastStr = text
        while(matches.length > 0) {
          let temp = matches.shift()
          let content =  lastStr.split(temp)[0]
          if (content) newText.push(_match(keyword, content))
          newText.push(temp)
          lastStr = lastStr.split(`${content || ''}${temp}`)[1] || ''
        }
        lastStr && newText.push(lastStr)
        return newText.join('')
      } else {
        return _match(keyword, text)
      }
    } else {
      return text
    }
  }

你可能感兴趣的:(React,javascript,前端,开发语言,react)