简单描述一下:
页面接受一个参数,id之类的,通过这个参数异步获取对应的html内容(完整的html,里面可能会含有 script标签,包括引用某些库,或者自己写在script标签里面的js代码),数据加载完成后渲染获取到的内容。
实现:
-
根据id获取数据html内容,本demo是通过 store 模拟
-
将获取到的html覆盖插入到html标签
let htmlDom = document.getElementsByTagName("html")[0] htmlDom.innerHTML = this.caseList[id].text
-
获取所有的script标签并转换成标准数组
let scripts = document.getElementsByTagName("script"); scripts = Array.prototype.slice.call(scripts);
-
对script标签遍历操作:
保存父节点以便之后能插入到对应的位置
判断是引用外链还是内联代码
创建一个新的script标签,把内容赋值
移除当前script标签
按顺序保存到队列中,以promise方式保证执行顺序const parentNode = item.parentNode; const isLink = item.src ? true : false; // 创建新的script标签 let newScript = document.createElement("script"); if (isLink) { newScript.src = item.src; } else { newScript.innerHTML = item.innerHTML; } // 移除旧的script标签 parentNode.removeChild(item); // 封装成promise,push进队列 scriptList.push(() => { return that._loadScript(parentNode, newScript); });
-
按顺序执行插入到对应的父节点里面
scriptList.reduce((promise, fn) => { return promise.then(fn); }, Promise.resolve());
完整代码:
<!--
* @Author: your name
* @Date: 2021-02-22 11:37:44
* @LastEditTime: 2021-03-10 17:00:53
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \eidt-demo\src\views\caseDetail.vue
-->
<template>
<div id="detailID" class="app-container" ref="htmlContainer" style="height:100vh"></div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {};
},
computed: {
...mapState({
caseList: "case",
}),
},
beforeCreate() {},
mounted() {
let that = this;
let id = this.$route.query.id;
let scriptList = [];
// 插入html代码
let htmlDom = document.getElementsByTagName("html")[0];
// 此处把数据放在store中模拟
htmlDom.innerHTML = this.caseList[id].text;
// 获取所有的script标签
let scripts = document.getElementsByTagName("script");
// 伪数组转换
scripts = Array.prototype.slice.call(scripts);
scripts.map((item) => {
// 保存父节点以便插入到对应的位置
const parentNode = item.parentNode;
const isLink = item.src ? true : false;
// 创建新的script标签
let newScript = document.createElement("script");
if (isLink) {
newScript.src = item.src;
} else {
newScript.innerHTML = item.innerHTML;
}
// 移除旧的script标签
parentNode.removeChild(item);
// 封装成promise,push进队列
scriptList.push(() => {
return that._loadScript(parentNode, newScript);
});
});
// 按顺序执行插入
scriptList.reduce((promise, fn) => {
return promise.then(fn);
}, Promise.resolve());
},
methods: {
// 封装成promise形式
_loadScript(parentNode, scriptNode) {
return new Promise((resolve, reject) => {
// 添加到对应的父节点之下
parentNode.appendChild(scriptNode);
// 状态更新,返回resolve
scriptNode.onload = scriptNode.onreadystatechange = function () {
resolve();
};
});
},
},
};
</script>
<style>
</style>