美文网首页
es6实现简单模板编译

es6实现简单模板编译

作者: Stevenzwzhai | 来源:发表于2017-01-15 15:49 被阅读624次

    现在有各种框架,其中一个主要模块就是关于template。最火的vue、react等框架,在这一块上也是是下足了功夫。我也想写一个自己的模板编译工具,所以就做了个简单的实现,主要是使用es6的反引号编译。

    1.选择

    这里使用es6的反引号去编译文本节点,只要把数据放在scope中,我们就可以使用反引号加“${}”的方式去把变量替换掉模板中的内容。

    2.编译内容

    首先,我尝试去直接编译一个文本,让变量能够被填充,模板这么写

    <div id="app">
         <p>your name is ${name}</p>
         <p>your age is ${age}</p>
    </div>
    

    模板中${}中的内容是要被替换的。首先我们获取文本字符串

    const root = document.querySelector('#app');
    let htmlFragment = root.innerHTML;
    

    然后我们要找出需要替换的变量名,这里用正则查找

    const templateReg = /\${([^{}])+}/g;
    let res = null;
    let keyArray = [];
    //把找到的变量存起来
    while(res = reg.exec(htmlFragment)){
         let key = res[0].slice(2,res[0].length-1);
         keyArray.push(key);
    }
    

    我们在js中定义的数据格式是这样的

    let data = {
         name:"javascript",
         age:"22"
    }
    

    接下来,我们把js中的数据格式替换掉模板中的

     for(let item of keyArray){
         let nReg = new RegExp("\\${"+item+"}","g");           
         htmlFragment = htmlFragment.replace(nReg, '${data["'+item+'"]}');
    }   
    

    这里说一下为什么要替换,首先是es6中编译字符串中的变量,这个变量必须在scope中,然后,我们的数据不可能是就像一个一个的变量,那样要定义太多,还有就是模板中尽量写法简洁。所以这里把简洁的变量替换为正真的scope中的变量。因为是要动态替换,所以正则表达式每次都要重新定义(注意转义)。
    最后就是如何编译的问题,因为我们拿到的是个字符串,而es6是要用反引号来编译,所以这里就需要拼接反引号和字符串进行编译,大家最容易想到的就是eval,但是介于它可能会带来一些不可预知的东西,所以我们使用new Function()的方式。

    let str = new Function("return `"+htmlFragment+"`");
    root.innerHTML = "";
    //这个方法很久之前就有了,并不是最新出的
    root.insertAdjacentHTML('afterbegin',str);
    

    3.编译模板

    这里借鉴vue的节点编译方式,主要就是对元素节点和文本节点的处理。由于并没有做循环渲染,所以目前只做了对文本节点的处理。基本的思想还是以一颗树的形式去一层一层的编译。

        class Compile{   constructor(node){      this.compileNode(node);      node.hasChildNodes() ? this.compileNodeList(node.childNodes) : null;   }   compileNodeList(nodeList){      let childListFn, node;      for(node of nodeList){         this.compileNode(node);         node.hasChildNodes ? this.compileNodeList(node.childNodes) : null;      }   }   compileNode(node){      console.log(node);      if(node.nodeType == 1){         this.compileElement(node);      }else if(node.nodeType == 3){         this.compileText(node);      }   }   compileElement(node){      //解析指令   }   compileText(node){      //解析模板      node.data;      node.data = this.compileTemplate(node.data)();   }   compileTemplate(textFragment){      let res = null;      let keyArray = [];      while(res = templateReg.exec(textFragment)){         let key = res[0].slice(2,res[0].length-1);         keyArray.push(key);      }      for(let item of keyArray){         let nReg = new RegExp("\\${"+item+"}","g");         console.log(nReg.test(textFragment));         textFragment = textFragment.replace(nReg, '${data["'+item+'"]}');      }      return new Function("return `"+textFragment+"`");   }}//new这个对象即可new Compile(root);
    

    全部的可以去github上看,这个后续也会加强功能。https://github.com/Stevenzwzhai/plugs/tree/master/es6-template

    相关文章

      网友评论

          本文标题:es6实现简单模板编译

          本文链接:https://www.haomeiwen.com/subject/mtnybttx.html