zoukankan      html  css  js  c++  java
  • 构建语法树和解析语法树

    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(/<([dD]+?)>/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=" 100px;">这是一<section>222<br>这是一个s<section>这是一个section</section>ection</section>个section</section>');
    // const editHtml=astDataToEditHtml(astData)
    // console.log(editHtml)
    module.exports={
      templateToAstData,
      astDataToEditHtml
    }
    

      

  • 相关阅读:
    element-ui 中dialog居中
    点击element-ui表格中的图标,上方显示具体的文字描述
    第一节:模板模式——需求说明&基本介绍
    第六节:代理模式——总结
    第五节:代理模式——代理模式的变体
    第四节:代理模式——cglib代理
    第三节:代理模式——动态代理
    第二节:代理模式——静态代理
    第一节:代理模式——基本介绍
    第四节:享元模式——总结
  • 原文地址:https://www.cnblogs.com/caoke/p/14272594.html
Copyright © 2011-2022 走看看