前言:
承接上篇【dart-skeleton】自动生成骨架屏项目内容,这一篇主要来说一下第一块内容脚本篇,也是我们整个项目的关键部分。
解析入口参数:
- 下图中的opts数组就是需要传入脚本的内容,参数主要涉及类型三种,通过的string类型,function类型,object类型,这里面将对象类型的数据进行序列化成字符串,将函数类型的数据也转换为字符串进行传递。
- 在接收到数据后进行解析的时候,因为函数已字符串的形式进行传递,我们这块就使用
eval
进行包装,由于各种编译场景均不太允许直接使用eval
函数,所以我们进行了重新赋值的处理,编程了_eval
。对象类型进行反序列化为对象,字符串则直接接受即可。
排除无效/干扰元素:
由于页面各式各样,不合理的布局将会造成解析的结果非常糟糕,我们可以通过指定元素选项来进行过滤,由于页面也会存在一些被隐藏或透明的元素我们也将跳过。
需要隐藏的类型包括:
- display属性为none的节点;
- visibility属性为hidden的节点;
- opacity属性为0的节点。
需要跳过的元素的处理:
我们在入口参数提供了一个includeElement
函数,这个函数可以接收一个dom节点
和一个绘制函数,当接收到dom节点
后通过对选项进行筛选反返回为false
即可跳过对应元素。
const isCustomSkip = typeof this.includeElement === "function" && this.includeElement(node, this.drawBlock) == false; 复制代码
绘制关键元素:
说了不需要绘制的元素,那么需要绘制的元素都包括什么呢?如下列举:
- 当元素设置了
background-image
属性时,如果解析到内容包含url
地址则需要绘制; - 当遍历到该元素的子元素包含文本类型的节点且节点内容不为空时需要绘制;
- 遍历当前的元素为文本类型且节点内容不为空时需要绘制;
- 当元素在我们的预设列表中存在时需要绘制。
注:
- 以上条件满足一项即需要绘制。
- 当我们设置需要绘制头部的时候,如果头部的高度会遮挡一部分元素,那么这部分元素可跳过不绘制。
这里贴出关键的绘制函数:
drawBlock({ width, height, top, left, zIndex = 999, background = this.background, radius, subClas = false, }: DrawBlock) { const styles = [`height:${height}%`]; if (!subClas) { styles.push(`top:${top}%`, `left:${left}%`, `width:${width}%`); } if (classProps.zIndex !== zIndex) { styles.push(`z-index:${zIndex}`); } if (classProps.background !== background) { styles.push(`background:${background}`); } radius && radius != "0px" && styles.push(`border-radius:${radius}`); this.blocks.push( `<div class="_${subClas ? " __" : ""}" style="${styles.join(";")}"></div>` ); } 复制代码
预览绘制效果:
这一块相对简单很多,就是一个dom操作将我们处理得到的字符串拆入到目标页面的body节点中:
const { body } = document; const blocksHTML = this.blocks.join(""); const div = document.createElement("div"); div.innerHTML = blocksHTML; body.appendChild(div); 复制代码
说明: 此项目是在dps项目的基础上重写的一个Ts版本,目的是学习思路方便后续改造。