index.js 4.0 KB

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