| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title></title>
- </head>
- <body>
- <script>
-
- class FileContentController {
- static startStr = `<span class='keyword' style='background:yellow;'>`
- static endStr = `</span>`
- static timer = null
- constructor(options) {}
- // 渲染
- render(content, keyword) {
- if (!content || typeof content !== 'string') return
- const html_match = content.match(/\<html.+\>.+[\<\/html\>]{0,1}/)
- let html = (html_match && html_match[0]) ? html_match[0] : ''
- if (keyword && typeof keyword === 'string') {
- html = this.highlightKeyword(html, keyword) || ''
- }
- document.documentElement.innerHTML = html.replace('<html>', '').replace('</html>', '')
- if (keyword && typeof keyword === 'string') {
- this.scrollToKeyword()
- }
- }
- // 高亮关键词
- highlightKeyword(html, keyword) {
- if (!html || typeof html !== 'string' || !keyword || typeof keyword !== 'string') return
- const startStr = FileContentController.startStr
- const endStr = FileContentController.endStr
- const splitedKeyword = keyword.split(/\n+/).map((item, i) => ({ index: i, arr: [item] }))
- if (splitedKeyword && splitedKeyword.length) {
- const arrList = []
- splitedKeyword.forEach((word, index) => {
- if (word.arr[0].includes(' ')) {
- arrList.push({
- index,
- arr: word.arr[0].split(/\s+/).filter(i => i !== '')
- })
- }
- })
- arrList.forEach(item => {
- splitedKeyword[item.index].arr = item.arr
- })
- const newSplitedKeyword = []
- splitedKeyword.reduce((list, word) => {
- word.arr.forEach(i => { list.push(i) })
- return list
- }, newSplitedKeyword)
- newSplitedKeyword.forEach((item, i) => {
- let reg = null
- if (!this.hasEscapeCharacter(item)) {
- reg = new RegExp(item, 'g')
- } else {
- let str = ''
- if (item.includes('.')) {
- const arr = item.split('.')
- str += arr.join('\\.')
- }
- reg = new RegExp(str, 'g')
- }
-
- // matchAll匹配结果
- const matchedAll = Array.from(html.matchAll(reg))
- // indexOf查找匹配位置
- const index = html.indexOf(item.replace('\\', ''))
- if (!matchedAll.length) { // matchAll没有匹配到
- if (index !== -1) {
- const list = Array.from(html)
- list.splice(index, item.length, `${startStr}${item}${endStr}`)
- html = list.join('')
- }
- } else { // matchAll匹配到结果
- const preIndex = html.indexOf(newSplitedKeyword[i - 1])
- const nextIndex = html.lastIndexOf(newSplitedKeyword[i + 1])
- const target = matchedAll.find(i => (i.index > preIndex) && (i.index < nextIndex))
- if (target) {
- const list = Array.from(html)
- list.splice(target.index, target[0].length, `${startStr}${target[0]}${endStr}`)
- html = list.join('')
- }
- }
- })
- }
- return html
- }
- // 滚动至第一个有内容的关键词
- scrollToKeyword() {
- let timer = FileContentController.timer
- if (timer) clearTimeout(timer)
- const keywords = Array.from(document.querySelectorAll('.keyword'))
- const target = keywords.find(item => !!item.innerHTML)
- if (!target) {
- if (document.readyState === "complete") {
- if (timer) clearTimeout(timer)
- } else {
- timer = setTimeout(() => {
- this.scrollToKeyword()
- }, 100)
- }
- } else {
- if (timer) clearTimeout(timer)
- const position = target.getBoundingClientRect().top
- document.body.scrollTop = position
- document.documentElement.scrollTop = position
- }
- }
- // 是否有需要转义的字符
- hasEscapeCharacter(str) {
- return str.includes('.') ||
- str.includes('"') ||
- str.includes('“') ||
- str.includes('”') ||
- str.includes('(') ||
- str.includes(')') ||
- str.includes('(') ||
- str.includes(')')
- }
- }
- window.addEventListener('message', handleMessage, false)
- // 接收方的 message event handler
- function handleMessage({ data }) {
- if (data.fileContent && typeof data.fileContent === 'string') {
- const content = data.fileContent.replace(/\n/g, '')
- const keyword = data.keyword || ''
- const controller = new FileContentController()
- controller.render(content, keyword)
- // // MDN 建议在处理消息前要先检查发送方的域名,防止恶意消息
- // if (event.origin === 'http://www.example.com') {
- // // 发送回执给发送方
- // event.source.postMessage('Message received', event.origin);
- // }
- }
- }
- </script>
- </body>
- </html>
|