index.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /**
  2. * @fileoverview search 插件
  3. */
  4. function Search (vm) {
  5. /**
  6. * @description 关键词搜索
  7. * @param {regexp|string} key 要搜索的关键词
  8. * @param {boolean} anchor 是否将搜索结果设置为锚点
  9. * @param {string} style 搜索结果的样式
  10. */
  11. vm.search = function (key, anchor, style = 'background-color:yellow') {
  12. const res = []
  13. const stack = [];
  14. // 遍历搜索
  15. (function traversal (nodes) {
  16. for (let i = 0; i < nodes.length; i++) {
  17. let node = nodes[i]
  18. if (node.type === 'text' && key) {
  19. const text = node.text
  20. const arr = text.split(key)
  21. if (arr.length > 1) {
  22. node = {
  23. name: 'span',
  24. attrs: {},
  25. type: 'node',
  26. c: 1,
  27. s: 1,
  28. children: []
  29. }
  30. vm.$set(nodes, i, node)
  31. for (let j = 0; j < arr.length; j++) {
  32. if (arr[j]) {
  33. node.children.push({
  34. type: 'text',
  35. text: arr[j]
  36. })
  37. }
  38. if (j !== arr.length - 1) {
  39. // 关键词转为一个 span
  40. node.children.push({
  41. name: 'span',
  42. attrs: {
  43. id: anchor ? 'search' + (res.length + 1) : undefined, // 用于锚点的 id
  44. style: style
  45. },
  46. // #ifdef VUE3
  47. c: 1,
  48. // #endif
  49. children: [{
  50. type: 'text',
  51. text: key instanceof RegExp ? key.exec(text)[0] : key
  52. }]
  53. })
  54. res.push(node.children[node.children.length - 1].attrs)
  55. }
  56. }
  57. if (key instanceof RegExp) {
  58. key.exec(text)
  59. }
  60. if (anchor) {
  61. for (let l = stack.length; l--;) {
  62. if (stack[l].c) {
  63. break
  64. } else {
  65. vm.$set(stack[l], 'c', 1)
  66. }
  67. }
  68. }
  69. }
  70. } else if (node.s) {
  71. let text = ''
  72. // 复原上一次的结果
  73. for (let k = 0; k < node.children.length; k++) {
  74. const child = node.children[k]
  75. if (child.text) {
  76. text += child.text
  77. } else {
  78. text += child.children[0].text
  79. }
  80. }
  81. vm.$set(nodes, i, {
  82. type: 'text',
  83. text
  84. })
  85. if (key && (key instanceof RegExp ? key.test(text) : text.includes(key))) {
  86. i--
  87. }
  88. } else if (node.children) {
  89. stack.push(node)
  90. traversal(node.children)
  91. stack.pop()
  92. }
  93. }
  94. })(vm.nodes)
  95. return new Promise(function (resolve) {
  96. setTimeout(() => {
  97. resolve({
  98. num: res.length, // 结果数量
  99. /**
  100. * @description 高亮某一个结果
  101. * @param {number} i 第几个
  102. * @param {string} hlstyle 高亮的样式
  103. */
  104. highlight (i, hlstyle = 'background-color:#FF9632') {
  105. if (i < 1 || i > res.length) return
  106. if (this.last) {
  107. res[this.last - 1].style = style
  108. }
  109. this.last = i
  110. res[i - 1].style = hlstyle
  111. },
  112. /**
  113. * @description 跳转到搜索结果
  114. * @param {number} i 第几个
  115. * @param {number} offset 偏移量
  116. */
  117. jump: anchor
  118. ? (i, offset) => {
  119. if (i > 0 && i <= res.length) {
  120. vm.navigateTo('search' + i, offset)
  121. }
  122. }
  123. : undefined
  124. })
  125. }, 200)
  126. })
  127. }
  128. }
  129. module.exports = Search