133 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
/**
 | 
						|
 * @fileoverview search 插件
 | 
						|
 */
 | 
						|
function Search (vm) {
 | 
						|
  /**
 | 
						|
   * @description 关键词搜索
 | 
						|
   * @param {regexp|string} key 要搜索的关键词
 | 
						|
   * @param {boolean} anchor 是否将搜索结果设置为锚点
 | 
						|
   * @param {string} style 搜索结果的样式
 | 
						|
   */
 | 
						|
  vm.search = function (key, anchor, style = 'background-color:yellow') {
 | 
						|
    const res = []
 | 
						|
    const stack = [];
 | 
						|
 | 
						|
    // 遍历搜索
 | 
						|
    (function traversal (nodes) {
 | 
						|
      for (let i = 0; i < nodes.length; i++) {
 | 
						|
        let node = nodes[i]
 | 
						|
        if (node.type === 'text' && key) {
 | 
						|
          const text = node.text
 | 
						|
          const arr = text.split(key)
 | 
						|
          if (arr.length > 1) {
 | 
						|
            node = {
 | 
						|
              name: 'span',
 | 
						|
              attrs: {},
 | 
						|
              type: 'node',
 | 
						|
              c: 1,
 | 
						|
              s: 1,
 | 
						|
              children: []
 | 
						|
            }
 | 
						|
            vm.$set(nodes, i, node)
 | 
						|
            for (let j = 0; j < arr.length; j++) {
 | 
						|
              if (arr[j]) {
 | 
						|
                node.children.push({
 | 
						|
                  type: 'text',
 | 
						|
                  text: arr[j]
 | 
						|
                })
 | 
						|
              }
 | 
						|
              if (j !== arr.length - 1) {
 | 
						|
                // 关键词转为一个 span
 | 
						|
                node.children.push({
 | 
						|
                  name: 'span',
 | 
						|
                  attrs: {
 | 
						|
                    id: anchor ? 'search' + (res.length + 1) : undefined, // 用于锚点的 id
 | 
						|
                    style: style
 | 
						|
                  },
 | 
						|
                  // #ifdef VUE3
 | 
						|
                  c: 1,
 | 
						|
                  // #endif
 | 
						|
                  children: [{
 | 
						|
                    type: 'text',
 | 
						|
                    text: key instanceof RegExp ? key.exec(text)[0] : key
 | 
						|
                  }]
 | 
						|
                })
 | 
						|
                res.push(node.children[node.children.length - 1].attrs)
 | 
						|
              }
 | 
						|
            }
 | 
						|
            if (key instanceof RegExp) {
 | 
						|
              key.exec(text)
 | 
						|
            }
 | 
						|
            if (anchor) {
 | 
						|
              for (let l = stack.length; l--;) {
 | 
						|
                if (stack[l].c) {
 | 
						|
                  break
 | 
						|
                } else {
 | 
						|
                  vm.$set(stack[l], 'c', 1)
 | 
						|
                }
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
        } else if (node.s) {
 | 
						|
          let text = ''
 | 
						|
          // 复原上一次的结果
 | 
						|
          for (let k = 0; k < node.children.length; k++) {
 | 
						|
            const child = node.children[k]
 | 
						|
            if (child.text) {
 | 
						|
              text += child.text
 | 
						|
            } else {
 | 
						|
              text += child.children[0].text
 | 
						|
            }
 | 
						|
          }
 | 
						|
          vm.$set(nodes, i, {
 | 
						|
            type: 'text',
 | 
						|
            text
 | 
						|
          })
 | 
						|
          if (key && (key instanceof RegExp ? key.test(text) : text.includes(key))) {
 | 
						|
            i--
 | 
						|
          }
 | 
						|
        } else if (node.children) {
 | 
						|
          stack.push(node)
 | 
						|
          traversal(node.children)
 | 
						|
          stack.pop()
 | 
						|
        }
 | 
						|
      }
 | 
						|
    })(vm.nodes)
 | 
						|
 | 
						|
    return new Promise(function (resolve) {
 | 
						|
      setTimeout(() => {
 | 
						|
        resolve({
 | 
						|
          num: res.length, // 结果数量
 | 
						|
          /**
 | 
						|
           * @description 高亮某一个结果
 | 
						|
           * @param {number} i 第几个
 | 
						|
           * @param {string} hlstyle 高亮的样式
 | 
						|
           */
 | 
						|
          highlight (i, hlstyle = 'background-color:#FF9632') {
 | 
						|
            if (i < 1 || i > res.length) return
 | 
						|
            if (this.last) {
 | 
						|
              res[this.last - 1].style = style
 | 
						|
            }
 | 
						|
            this.last = i
 | 
						|
            res[i - 1].style = hlstyle
 | 
						|
          },
 | 
						|
          /**
 | 
						|
           * @description 跳转到搜索结果
 | 
						|
           * @param {number} i 第几个
 | 
						|
           * @param {number} offset 偏移量
 | 
						|
           */
 | 
						|
          jump: anchor
 | 
						|
            ? (i, offset) => {
 | 
						|
                if (i > 0 && i <= res.length) {
 | 
						|
                  vm.navigateTo('search' + i, offset)
 | 
						|
                }
 | 
						|
              }
 | 
						|
            : undefined
 | 
						|
        })
 | 
						|
      }, 200)
 | 
						|
    })
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
module.exports = Search
 |