const domTags=['div','section','img','p','span']
//深度遍历html节点
function depthSearch(node,childProp='children'){
const nodeList=[]
const depthEach=function(item){
nodeList.push(item);
if(item[childProp]){
for(let k in item[childProp]){
depthEach(item[childProp][k]);
}
}
}
depthEach(node);
return nodeList;
}
//模板转语法树
function templateToAstData(template) {
console.log(template)
let deep=0;
const astTree={
node:{
id:0,
deep:0,
child:[],
},
id:0,
idMap:{},
getNode(deep) {
let node=this.node
for(let i=1;i<deep+1;i++){
node=node.child[node.child.length-1]
}
return node;
},
createNode(deep,propStr) {
let node=this.node
//创建空元素
for(let i=1;i<deep+1;i++){
if(!node.child){node.child=[]}
if(i===deep){
const nNode={
id:++this.id,
deep:deep,
}
this.idMap[nNode.id]=nNode
node.child.push(nNode)
}
node=node.child[node.child.length-1]
}
const props={md5_id:node.id}
if(propStr){
propStr.replace(/(\w+)=(['"])(.+?)\2/g,function (m,p1,p2,p3) {
props[p1]=p3
})
}
node.props=props;
return node;
},
createText(deep,text){
const node=this.createNode(deep)
node.tag='_text';
node.text=text;
return node;
}
};
let pathArr=[]
let preRange=[0,0];
template.replace(/<([\d\D]+?)>/gi,function (m,p1,p2) {
let curDeep=deep;
//开头<div>
if(/^([a-z]\w*)/i.test(p1)){
const tag=RegExp.$1.toLocaleLowerCase();
let last=p1.replace(tag,'')
if(tag==='br'||last[last.length-1]==='/'){
if(pathArr[deep]===undefined){
pathArr[deep]={
startRange:[p2,p2+m.length],
endRange:[p2,p2+m.length],
isEnd:1,
tag:tag,
};
}
}else{
pathArr[deep]={
startRange:[p2,p2+m.length],
isEnd:0,
tag:tag,
}
deep++;
}
}else if(/^\/([a-z]\w*)$/i.test(p1)){ //结尾 </div>
const tag=RegExp.$1.toLocaleLowerCase();
if(pathArr[deep-1]&&tag===pathArr[deep-1].tag){
deep--;
curDeep=deep
if(tag===pathArr[curDeep].tag){
pathArr[curDeep].isEnd=2;
pathArr[curDeep].endRange=[p2,p2+m.length];
}
}else{
pathArr[deep]={
startRange:[p2,p2+m.length],
endRange:[p2,p2+m.length],
isEnd:-1,
};
}
}
const isEnd=pathArr[curDeep].isEnd;
const tag=pathArr[curDeep].tag;
if(isEnd===0){
if(preRange[1]<p2){
const text=template.substring(preRange[1],p2)
if(/\S/.test(text)){
//创建文字元素
astTree.createText(curDeep,text)
}
}
//创建空元素
astTree.createNode(curDeep,p1.substring(tag.length,p1.length))
}else if(isEnd===1){
if(preRange[1]<p2){
const text=template.substring(preRange[1],p2)
if(/\S/.test(text)){
//创建文字元素
astTree.createText(curDeep,text)
}
}
//创建当前元素
const node=astTree.createNode(curDeep,p1.substring(tag.length,p1.length))
Object.assign(node,pathArr[curDeep])
}else if(isEnd===2){
if(preRange[1]<p2){
const text=template.substring(preRange[1],p2)
if(/\S/.test(text)){
//创建文字元素
astTree.createText(curDeep+1,text)
}
}
const node=astTree.getNode(curDeep)
Object.assign(node,pathArr[curDeep])
}
preRange=[p2,p2+m.length]
})
return astTree;
}
//语法树转可编辑模板
function astDataToEditHtml(astTree) {
const astData=astTree.node
function getTextByNode(node) {
//dom 对应的属性空间
const props=node.props
let pstr=''
for(let name in props){
pstr=pstr+` ${name}="${props[name]}"`;
}
if(node.tag==='_text'){
return [node.text]
}else if(node.isEnd===1){
return [`<${node.tag}${pstr}/>`]
}else if(node.isEnd===2){
return [`<${node.tag}${pstr}>`,`</${node.tag}>`]
}
return ['']
}
const list=depthSearch(astData,'child')
let preDeep=-1;
const endCache=[]
let html=''
for(let i=0;i<list.length;i++){
const node=list[i];
const arr=getTextByNode(node)
if(node.deep<=preDeep){
for(let i=preDeep;i>=node.deep;i--){
html=html+endCache[i]
}
}
endCache[node.deep]=arr[1]||''
html=html+arr[0]
preDeep=node.deep;
}
for(let i=preDeep;i>=0;i--){
html=html+endCache[i]
}
return html;
}
// const astData=templateToAstData('<section name="222" style="width: 100px;">这是一<section>222<br>这是一个s<section>这是一个section</section>ection</section>个section</section>');
// const editHtml=astDataToEditHtml(astData)
// console.log(editHtml)
module.exports={
templateToAstData,
astDataToEditHtml
}