我们要做页面的回溯,首先我们需要获取当前页面的所有的html内容然后在需要回溯的时候重新模拟回放出来,当然你可能会说你可以直接通过iframe把目前页面引入也是可以的。这个方式不是不可以,只不过限制太多了,比如,登录状态就是个问题,而直接获取页面的内容在模拟回放就没有这个问题。当然了,还有很多的问题了~
要获取html内容,我们可能想到的就是innerHTML
或者outerHTML
这两个方法了。
1
| const pageHTML = document.documentElement.outerHTML
|
通过上述方法我们就可以拿到想要的,然而当我们把获取内容放到本地测试的时候发现了问题,页面是不展示的。当然看有的是展示的,为什么呢?通过对代码的分析的出来,有些css和js的引入是相对当前域名的,例如:
1 2 3
| <link href="/css/a.css"/> <script src="./js/b.js"></script> <img src="./images/xxx.jpg" />
|
找出问题下面就是解决问题了,如果把上面的换成下面的样子呢?
1 2 3
| <link href="https:xxxx.com/css/a.css"/> <script src="https:xxxx.com/js/b.js"></script> <img src="https:xxxx.com/images/xxx.jpg" />
|
第一感觉还是正则,使用正则找出所有的情况然后进行替换。这种方案肯定是可行的,但是需要考虑的比较多,咱们今天使用的是另外一个方案-template
方式。
1 2 3
| <template> <img src="./images/xxx.jpg" /> </template>
|
如果你不了解template
可以去看看文档,这里我们简单的引用下文档:
HTML 内容模板(<template>
)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以 (原文为 may be) 在运行时使用 JavaScript 实例化。
将模板视为一个可存储在文档中以便后续使用的内容片段。虽然解析器在加载页面时确实会处理<template>
元素的内容,但这样做只是为了确保这些内容有效;但元素内容不会被渲染。
此元素仅包含全局属性。但, HTMLTemplateElement
有个属性: content
, 这个属性是只读的DocumentFragment
包含了模板所表示的 DOM 树。
通过官方的文档我们知道,template就是个用于存放内容的模板并且不会展示内容,我们以前使用script和textarea来做现在有官方的标签了就更强大了。
1 2 3 4 5
| const pageHtml = document.documentElement.outerHTML; const template = document.createElement('template') template.innerHTML = pageHtml
const scripts = template.content.querySelectorAll("script")
|
从上面可以看出,content可以让我们使用dom操作,非常的简单。下面我们写出一个完整的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function getPageCodeAndEncode() { const pageHtml = document.documentElement.outerHTML; let template = document.createElement('template') template.innerHTML = pageHtml const scripts = template.content.querySelectorAll("script") const links = template.content.querySelectorAll("link") const images = template.content.querySelectorAll("img") links.forEach((el) => { el.href = el.href }) scripts.forEach((el) => { el.src = el.src }) images.forEach((el) => { el.src = el.src }) const newHtmlStr = template.innerHTML template = null return encodeURIComponent(newHtmlStr) }
|
上面是把html获取到然后处理成我们想要的样子然后返回,如果你看了template
的官方文档会发现,它里面不支持的标签还是有一些的。比如:html,head,body。所以我们输出的内容看着就是没有上面的三种标签的。这肯定不行我们怎么办呢?
这时候我们需要使用 DOMParser.parseFromString()
了,不了解的可以看下官方的文档
1 2 3 4 5 6 7 8 9
| function parsePageCode(code) { const decode = decodeURIComponent(code) const dom = new DOMParser().parseFromString(decode, 'text/html'); return { dom, domStr: dom.documentElement.outerHTML } }
|
上面方法是把处理好的代码转成标准的html,可以使用document.write写入文档即可。
1 2 3 4 5 6
| function parsePageCode(code) { const decode = decodeURIComponent(code) const dom = new DOMParser().parseFromString(decode, 'text/html'); document.write(dom.documentElement.outerHTML) }
|
有了以上两个方法我们就可以来我们本地重新模拟回放页面了。