对单元格进行实时渲染
当写完本系列后,我会把源代码分享出来给大家。本课程也会持续更新与矫正。欢迎留言指正!
功能简介
前面第一节内容的时候,提到的模板,使用的是HTML标签,现在需要开始做一个核心功能就是把读取到的excel 文件里的内容渲染到页面中来。
在渲染方面,我们一般已知的就有比较知名的 Angular, React, Vue 等等框架,但是由于这里将会有很多定制化的功能要做,加载第三方框架的话,就需要安装大量的第三方辅助包,会使得整个项目更加复杂和臃肿。
还有一个更关键的原因是,第三方框架的版本更新迭代,会影响到项目的复杂度。综上考虑,促使我要自己实现这个渲染器
工作流的结构
HTML 标签元素特点分析
一个普通的 HTML 标签元素长什么样?
<div id="iamid" title="title" style="color:#ff0000;" data-dataKey="dataValue">
我是文本内容
</div>
所以,我们要先定义一个渲染器接收的数据流结构,我给它起名为:渲染树。渲染树的数据结构应该是长什么样的呢?请看下面:
[
{
"Tag" : "div",
"ID" : "iamid",
"title" : "title",
"ClassName" : "",
"Style" : "",
"Data" : [
{
"k":"dataKey",
"v":"dataValue"
}
],
"Text":"我是文本内容",
"Action":{
"click":function(){
console.log("click Action")},
"change":function(){
console.log("change Action")},
},
"Child":[
{
"Tag" : "span",
"ClassName" : "",
"Style" : "",
"Data" : [
{
"k":"dataKey",
"v":"dataValue"
}
],
"Text":"我是文本内容",
"Action":{
"click":function(){
console.log("click Action")},
"change":function(){
console.log("change Action")},
},
"Child":[]
}
]
}
]
属性分析:
属性 | 功能描述 |
---|---|
Tag | 标签(div, span, li, ul 等等) |
Data | data-* 属性用于存储页面或应用程序的私有自定义数据。 |
ID | 标签的ID |
ClassName | class 样式类的名称 |
Style | 样式 |
Action | 事件绑定 |
Child | 子标签,这是一个数组 |
渲染器的源代码
创建一个渲染器类
class renderDOM{
/**
* 初始化渲染器
*/
constructor() {
}
/**
* 创建一个渲染方法
*/
renderDOM(){
}
}
我把渲染器函数命名为:renderDOM
会传入四个参数:
- mainid(父级节点的ID)
- DomTree(整个渲染树)
- begin(渲染树的事件发生前,会执行 begin 函数)
- end(渲染树的事件发生后,会执行 end 函数)
renderDOM(mainid,DomTree,begin,end){
var begin = begin || function(){
console.log("begin")};
var end = end || function(){
console.log("end")};
var that = this;
var oMain = document.getElementById(mainid);
var fragment = document.createDocumentFragment();
var Celement;
var ChildList = [];
for(var i in DomTree){
if(typeof DomTree[i]["Tag"] === 'string'){
Celement = document.createElement(DomTree[i]["Tag"]);
if(typeof DomTree[i]["ID"] === 'string'){
Celement.setAttribute("id",DomTree[i]["ID"]);
}
if(typeof DomTree[i]["Title"] === 'string'){
Celement.setAttribute("title",DomTree[i]["Title"]);
}
if(typeof DomTree[i]["ClassName"] === 'string'){
Celement.setAttribute("class",DomTree[i]["ClassName"]);
}
if(typeof DomTree[i]["Style"] === 'string'){
Celement.setAttribute("style",DomTree[i]["Style"]);
}
if(typeof DomTree[i]["selected"] === 'string'){
Celement.setAttribute("selected",DomTree[i]["selected"]);
}
if(typeof DomTree[i]["Data"] === 'object'){
for(var j in DomTree[i]["Data"]){
Celement.setAttribute("data-"+DomTree[i]["Data"][j]["k"],DomTree[i]["Data"][j]["v"]);
}
}
if(typeof DomTree[i]["Contenteditable"] === 'string'){
// 该处可以设置 div 元素为可编辑区域
Celement.contenteditable = DomTree[i]["Contenteditable"];
}
if(typeof DomTree[i]["Text"] === 'string'){
Celement.innerHTML = DomTree[i]["Text"];
}
if(typeof DomTree[i]["Child"] === 'object'){
if(DomTree[i]["Child"].length>0){
ChildList.push({
"mainid" : DomTree[i]["ID"],
"DomTree" : DomTree[i]["Child"]
});
}
}
fragment.appendChild(Celement);
}
}
oMain.appendChild(fragment);
// 渲染子节点
if(ChildList.length>0){
for(var i in ChildList){
this.renderDOM(ChildList[i]["mainid"],ChildList[i]["DomTree"],begin,end);
}
}
}
渲染器新增了事件绑定
现在开始在渲染模块里面,新增一个事件方法,所有的事件创建之后都会存放在一个大集合里面。方便随时可以调用。
clickevent 就是用于存放所有事件的 map 对象集合。
在渲染器里,新增了对事件代码的绑定。
if(typeof DomTree[i]["Action"] === 'object'){
if(typeof DomTree[i]["Hotkey"] === 'string'){
// 设置热键
that.addKeyEvent(DomTree[i]["Hotkey"],(typeof DomTree[i]["Action"]["click"] === 'function')?DomTree[i]["Action"]["click"]:function(){
});
}
if(typeof DomTree[i]["Action"]["text"] === 'function'){
// 设置多语言界面
that.UIevent[DomTree[i]["ID"]] = DomTree[i]["Action"]["text"];
Celement.innerHTML = DomTree[i]["Action"]["text"](this.UITextSwitch);
}
that.clickevent[DomTree[i]["ID"]] = {
"begin":begin,
"readystatechange":(typeof DomTree[i]["Action"]["readystatechange"] === 'function')?DomTree[i]["Action"]["readystatechange"]:function(){
},
"click":(typeof DomTree[i]["Action"]["click"] === 'function')?DomTree[i]["Action"]["click"]:function(){
},
"dblclick":(typeof DomTree[i]["Action"]["dblclick"] === 'function')?DomTree[i]["Action"]["dblclick"]:function(){
},
"mousedown":(typeof DomTree[i]["Action"]["mousedown"] === 'function')?DomTree[i]["Action"]["mousedown"]:function(){
},
"mouseup":(typeof DomTree[i]["Action"]["mouseup"] === 'function')?DomTree[i]["Action"]["mouseup"]:function(){
},
"change":(typeof DomTree[i]["Action"]["change"] === 'function')?DomTree[i]["Action"]["change"]:function(){
},
"mousemove":(typeof DomTree[i]["Action"]["mousemove"] === 'function')?DomTree[i]["Action"]["mousemove"]:function(){
},
"mouseover":(typeof DomTree[i]["Action"]["mouseover"] === 'function')?DomTree[i]["Action"]["mouseover"]:function(){
},
"mouseout":(typeof DomTree[i]["Action"]["mouseout"] === 'function')?DomTree[i]["Action"]["mouseout"]:function(){
},
"contextmenu":(typeof DomTree[i]["Action"]["contextmenu"] === 'function')?DomTree[i]["Action"]["contextmenu"]:function(){
},
"end":end
};
if(typeof DomTree[i]["Action"]["mousewheel"] === 'function'){
Celement.addEventListener('mousewheel', DomTree[i]["Action"]["mousewheel"], false)
}
if(typeof DomTree[i]["Action"]["mousemove"] === 'function'){
Celement.addEventListener('mousemove', DomTree[i]["Action"]["mousemove"], false)
}
}
所以整个代码结构变成这样:
renderDOM(mainid,DomTree,begin,end){
var begin = begin || function(){
console.log("begin")};
var end = end || function(){
console.log("end")};
var that = this;
var oMain = document.getElementById(mainid);
var fragment = document.createDocumentFragment();
var Celement;
var ChildList = [];
for(var i in DomTree){
if(typeof DomTree[i]["Tag"] === 'string'){
Celement = document.createElement(DomTree[i]["Tag"]);
if(typeof DomTree[i]["ID"] === 'string'){
Celement.setAttribute("id",DomTree[i]["ID"]);
}
if(typeof DomTree[i]["Title"] === 'string'){
Celement.setAttribute("title",DomTree[i]["Title"]);
}
if(typeof DomTree[i]["ClassName"] === 'string'){
Celement.setAttribute("class",DomTree[i]["ClassName"]);
}
if(typeof DomTree[i]["Style"] === 'string'){
Celement.setAttribute("style",DomTree[i]["Style"]);
}
if(typeof DomTree[i]["selected"] === 'string'){
Celement.setAttribute("selected",DomTree[i]["selected"]);
}
if(typeof DomTree[i]["Data"] === 'object'){
for(var j in DomTree[i]["Data"]){
Celement.setAttribute("data-"+DomTree[i]["Data"][j]["k"],DomTree[i]["Data"][j]["v"]);
}
}
if(typeof DomTree[i]["Contenteditable"] === 'string'){
// 该处可以设置 div 元素为可编辑区域
Celement.contenteditable = DomTree[i]["Contenteditable"];
}
if(typeof DomTree[i]["Action"] === 'object'){
if(typeof DomTree[i]["Hotkey"] === 'string'){
// 设置热键
that.addKeyEvent(DomTree[i]["Hotkey"],(typeof DomTree[i]["Action"]["click"] === 'function')?DomTree[i]["Action"]["click"]:function(){
});
}
if(typeof DomTree[i]["Action"]["text"] === 'function'){
// 设置多语言界面
that.UIevent[DomTree[i]["ID"]] = DomTree[i]["Action"]["text"];
Celement.innerHTML = DomTree[i]["Action"]["text"](this.UITextSwitch);
}
that.clickevent[DomTree[i]["ID"]] = {
"begin":begin,
"readystatechange":(typeof DomTree[i]["Action"]["readystatechange"] === 'function')?DomTree[i]["Action"]["readystatechange"]:function(){
},
"click":(typeof DomTree[i]["Action"]["click"] === 'function')?DomTree[i]["Action"]["click"]:function(){
},
"dblclick":(typeof DomTree[i]["Action"]["dblclick"] === 'function')?DomTree[i]["Action"]["dblclick"]:function(){
},
"mousedown":(typeof DomTree[i]["Action"]["mousedown"] === 'function')?DomTree[i]["Action"]["mousedown"]:function(){
},
"mouseup":(typeof DomTree[i]["Action"]["mouseup"] === 'function')?DomTree[i]["Action"]["mouseup"]:function(){
},
"change":(typeof DomTree[i]["Action"]["change"] === 'function')?DomTree[i]["Action"]["change"]:function(){
},
"mousemove":(typeof DomTree[i]["Action"]["mousemove"] === 'function')?DomTree[i]["Action"]["mousemove"]:function(){
},
"mouseover":(typeof DomTree[i]["Action"]["mouseover"] === 'function')?DomTree[i]["Action"]["mouseover"]:function(){
},
"mouseout":(typeof DomTree[i]["Action"]["mouseout"] === 'function')?DomTree[i]["Action"]["mouseout"]:function(){
},
"contextmenu":(typeof DomTree[i]["Action"]["contextmenu"] === 'function')?DomTree[i]["Action"]["contextmenu"]:function(){
},
"end":end
};
if(typeof DomTree[i]["Action"]["mousewheel"] === 'function'){
Celement.addEventListener('mousewheel', DomTree[i]["Action"]["mousewheel"], false)
}
if(typeof DomTree[i]["Action"]["mousemove"] === 'function'){
Celement.addEventListener('mousemove', DomTree[i]["Action"]["mousemove"], false)
}
}
if(typeof DomTree[i]["Text"] === 'string'){
Celement.innerHTML = DomTree[i]["Text"];
}
if(typeof DomTree[i]["Child"] === 'object'){
if(DomTree[i]["Child"].length>0){
ChildList.push({
"mainid" : DomTree[i]["ID"],
"DomTree" : DomTree[i]["Child"]
});
}
}
fragment.appendChild(Celement);
}
}
oMain.appendChild(fragment);
// 渲染子节点
if(ChildList.length>0){
for(var i in ChildList){
this.renderDOM(ChildList[i]["mainid"],ChildList[i]["DomTree"],begin,end);
}
}
}