138 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
		
		
			
		
	
	
			138 lines
		
	
	
		
			4.0 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 obj = {}
							 | 
						||
| 
								 | 
							
								    const stack = []
							 | 
						||
| 
								 | 
							
								    const res = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // 遍历搜索
							 | 
						||
| 
								 | 
							
								    (function traversal (nodes, path) {
							 | 
						||
| 
								 | 
							
								      for (let i = 0; i < nodes.length; i++) {
							 | 
						||
| 
								 | 
							
								        const node = nodes[i]
							 | 
						||
| 
								 | 
							
								        if (node.type === 'text' && key) {
							 | 
						||
| 
								 | 
							
								          const arr = node.text.split(key)
							 | 
						||
| 
								 | 
							
								          const children = []
							 | 
						||
| 
								 | 
							
								          if (arr.length > 1) {
							 | 
						||
| 
								 | 
							
								            // 找到关键词
							 | 
						||
| 
								 | 
							
								            for (let j = 0; j < arr.length; j++) {
							 | 
						||
| 
								 | 
							
								              if (arr[j]) {
							 | 
						||
| 
								 | 
							
								                children.push({
							 | 
						||
| 
								 | 
							
								                  type: 'text',
							 | 
						||
| 
								 | 
							
								                  text: arr[j]
							 | 
						||
| 
								 | 
							
								                })
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								              if (j !== arr.length - 1) {
							 | 
						||
| 
								 | 
							
								                // 关键词转为一个 span
							 | 
						||
| 
								 | 
							
								                res.push(`${path}[${i}].children[${children.length}].attrs.style`)
							 | 
						||
| 
								 | 
							
								                children.push({
							 | 
						||
| 
								 | 
							
								                  name: 'span',
							 | 
						||
| 
								 | 
							
								                  attrs: {
							 | 
						||
| 
								 | 
							
								                    id: anchor ? 'search' + res.length : undefined, // 用于锚点的 id
							 | 
						||
| 
								 | 
							
								                    style
							 | 
						||
| 
								 | 
							
								                  },
							 | 
						||
| 
								 | 
							
								                  children: [{
							 | 
						||
| 
								 | 
							
								                    type: 'text',
							 | 
						||
| 
								 | 
							
								                    text: key instanceof RegExp ? key.exec(node.text)[0] : key
							 | 
						||
| 
								 | 
							
								                  }]
							 | 
						||
| 
								 | 
							
								                })
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (key instanceof RegExp) {
							 | 
						||
| 
								 | 
							
								              key.exec(node.text)
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (anchor) {
							 | 
						||
| 
								 | 
							
								              for (let l = stack.length; l--;) {
							 | 
						||
| 
								 | 
							
								                // 给父组件做标记,将该标签暴露出来
							 | 
						||
| 
								 | 
							
								                if (stack[l].c) {
							 | 
						||
| 
								 | 
							
								                  break
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                  obj[stack[l].path] = 1
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            obj[`${path}[${i}]`] = {
							 | 
						||
| 
								 | 
							
								              name: 'span',
							 | 
						||
| 
								 | 
							
								              c: anchor ? 1 : undefined,
							 | 
						||
| 
								 | 
							
								              s: 1,
							 | 
						||
| 
								 | 
							
								              children
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        } 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
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          nodes[i] = {
							 | 
						||
| 
								 | 
							
								            type: 'text',
							 | 
						||
| 
								 | 
							
								            text
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          if (key && (key instanceof RegExp ? key.test(text) : text.includes(key))) {
							 | 
						||
| 
								 | 
							
								            i--
							 | 
						||
| 
								 | 
							
								          } else {
							 | 
						||
| 
								 | 
							
								            obj[`${path}[${i}]`] = nodes[i]
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        } else if (node.children) {
							 | 
						||
| 
								 | 
							
								          stack.push({
							 | 
						||
| 
								 | 
							
								            path: `${path}[${i}].c`,
							 | 
						||
| 
								 | 
							
								            c: node.c || node.name === 'table'
							 | 
						||
| 
								 | 
							
								          })
							 | 
						||
| 
								 | 
							
								          traversal(node.children, `${path}[${i}].children`)
							 | 
						||
| 
								 | 
							
								          stack.pop()
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    })(vm.data.nodes, 'nodes')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return new Promise(function (resolve) {
							 | 
						||
| 
								 | 
							
								      vm.setData(obj, () => {
							 | 
						||
| 
								 | 
							
								        resolve({
							 | 
						||
| 
								 | 
							
								          num: res.length, // 结果数量
							 | 
						||
| 
								 | 
							
								          /**
							 | 
						||
| 
								 | 
							
								           * @description 高亮某一个结果
							 | 
						||
| 
								 | 
							
								           * @param {number} i 第几个
							 | 
						||
| 
								 | 
							
								           * @param {string} hlstyle 高亮的样式
							 | 
						||
| 
								 | 
							
								           */
							 | 
						||
| 
								 | 
							
								          highlight (i, hlstyle = 'background-color:#FF9632') {
							 | 
						||
| 
								 | 
							
								            if (i < 1 || i > res.length) return
							 | 
						||
| 
								 | 
							
								            const obj = {}
							 | 
						||
| 
								 | 
							
								            if (this.last) {
							 | 
						||
| 
								 | 
							
								              obj[res[this.last - 1]] = style
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            this.last = i
							 | 
						||
| 
								 | 
							
								            obj[res[i - 1]] = hlstyle
							 | 
						||
| 
								 | 
							
								            vm.setData(obj)
							 | 
						||
| 
								 | 
							
								          },
							 | 
						||
| 
								 | 
							
								          /**
							 | 
						||
| 
								 | 
							
								           * @description 跳转到搜索结果
							 | 
						||
| 
								 | 
							
								           * @param {number} i 第几个
							 | 
						||
| 
								 | 
							
								           * @param {number} offset 偏移量
							 | 
						||
| 
								 | 
							
								           */
							 | 
						||
| 
								 | 
							
								          jump: anchor
							 | 
						||
| 
								 | 
							
								            ? (i, offset) => {
							 | 
						||
| 
								 | 
							
								                if (i > 0 && i <= res.length) {
							 | 
						||
| 
								 | 
							
								                  vm.navigateTo('search' + i, offset)
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								            : undefined
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = Search
							 |