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
 |