htmlTemplate.html 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title></title>
  7. </head>
  8. <body>
  9. <script>
  10. class FileContentController {
  11. static startStr = `<span class='keyword' style='background:yellow;'>`
  12. static endStr = `</span>`
  13. static timer = null
  14. constructor(options) {}
  15. // 渲染
  16. render(content, keyword) {
  17. if (!content || typeof content !== 'string') return
  18. const html_match = content.match(/\<html.+\>.+[\<\/html\>]{0,1}/)
  19. let html = (html_match && html_match[0]) ? html_match[0] : ''
  20. if (keyword && typeof keyword === 'string') {
  21. html = this.highlightKeyword(html, keyword) || ''
  22. }
  23. document.documentElement.innerHTML = html.replace('<html>', '').replace('</html>', '')
  24. if (keyword && typeof keyword === 'string') {
  25. this.scrollToKeyword()
  26. }
  27. }
  28. // 高亮关键词
  29. highlightKeyword(html, keyword) {
  30. if (!html || typeof html !== 'string' || !keyword || typeof keyword !== 'string') return
  31. const startStr = FileContentController.startStr
  32. const endStr = FileContentController.endStr
  33. const splitedKeyword = keyword.split(/\n+/).map((item, i) => ({ index: i, arr: [item] }))
  34. if (splitedKeyword && splitedKeyword.length) {
  35. const arrList = []
  36. splitedKeyword.forEach((word, index) => {
  37. if (word.arr[0].includes(' ')) {
  38. arrList.push({
  39. index,
  40. arr: word.arr[0].split(/\s+/).filter(i => i !== '')
  41. })
  42. }
  43. })
  44. arrList.forEach(item => {
  45. splitedKeyword[item.index].arr = item.arr
  46. })
  47. const newSplitedKeyword = []
  48. splitedKeyword.reduce((list, word) => {
  49. word.arr.forEach(i => { list.push(i) })
  50. return list
  51. }, newSplitedKeyword)
  52. newSplitedKeyword.forEach((item, i) => {
  53. let reg = null
  54. if (!this.hasEscapeCharacter(item)) {
  55. reg = new RegExp(item, 'g')
  56. } else {
  57. let str = ''
  58. if (item.includes('.')) {
  59. const arr = item.split('.')
  60. str += arr.join('\\.')
  61. }
  62. reg = new RegExp(str, 'g')
  63. }
  64. // matchAll匹配结果
  65. const matchedAll = Array.from(html.matchAll(reg))
  66. // indexOf查找匹配位置
  67. const index = html.indexOf(item.replace('\\', ''))
  68. if (!matchedAll.length) { // matchAll没有匹配到
  69. if (index !== -1) {
  70. const list = Array.from(html)
  71. list.splice(index, item.length, `${startStr}${item}${endStr}`)
  72. html = list.join('')
  73. }
  74. } else { // matchAll匹配到结果
  75. const preIndex = html.indexOf(newSplitedKeyword[i - 1])
  76. const nextIndex = html.lastIndexOf(newSplitedKeyword[i + 1])
  77. const target = matchedAll.find(i => (i.index > preIndex) && (i.index < nextIndex))
  78. if (target) {
  79. const list = Array.from(html)
  80. list.splice(target.index, target[0].length, `${startStr}${target[0]}${endStr}`)
  81. html = list.join('')
  82. }
  83. }
  84. })
  85. }
  86. return html
  87. }
  88. // 滚动至第一个有内容的关键词
  89. scrollToKeyword() {
  90. let timer = FileContentController.timer
  91. if (timer) clearTimeout(timer)
  92. const keywords = Array.from(document.querySelectorAll('.keyword'))
  93. const target = keywords.find(item => !!item.innerHTML)
  94. if (!target) {
  95. if (document.readyState === "complete") {
  96. if (timer) clearTimeout(timer)
  97. } else {
  98. timer = setTimeout(() => {
  99. this.scrollToKeyword()
  100. }, 100)
  101. }
  102. } else {
  103. if (timer) clearTimeout(timer)
  104. const position = target.getBoundingClientRect().top
  105. document.body.scrollTop = position
  106. document.documentElement.scrollTop = position
  107. }
  108. }
  109. // 是否有需要转义的字符
  110. hasEscapeCharacter(str) {
  111. return str.includes('.') ||
  112. str.includes('"') ||
  113. str.includes('“') ||
  114. str.includes('”') ||
  115. str.includes('(') ||
  116. str.includes(')') ||
  117. str.includes('(') ||
  118. str.includes(')')
  119. }
  120. }
  121. window.addEventListener('message', handleMessage, false)
  122. // 接收方的 message event handler
  123. function handleMessage({ data }) {
  124. if (data.fileContent && typeof data.fileContent === 'string') {
  125. const content = data.fileContent.replace(/\n/g, '')
  126. const keyword = data.keyword || ''
  127. const controller = new FileContentController()
  128. controller.render(content, keyword)
  129. // // MDN 建议在处理消息前要先检查发送方的域名,防止恶意消息
  130. // if (event.origin === 'http://www.example.com') {
  131. // // 发送回执给发送方
  132. // event.source.postMessage('Message received', event.origin);
  133. // }
  134. }
  135. }
  136. </script>
  137. </body>
  138. </html>