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
|