js异步获取html内容插入并渲染

255 阅读1分钟

简单描述一下:

页面接受一个参数,id之类的,通过这个参数异步获取对应的html内容(完整的html,里面可能会含有 script标签,包括引用某些库,或者自己写在script标签里面的js代码),数据加载完成后渲染获取到的内容。

实现:

  1. 根据id获取数据html内容,本demo是通过 store 模拟

  2. 将获取到的html覆盖插入到html标签

     let htmlDom = document.getElementsByTagName("html")[0]
     htmlDom.innerHTML = this.caseList[id].text
    
  3. 获取所有的script标签并转换成标准数组

     let scripts = document.getElementsByTagName("script");
     scripts = Array.prototype.slice.call(scripts);
    
  4. 对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);
       });
    
  5. 按顺序执行插入到对应的父节点里面

    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>