JavaScript to write your own template parser

Source: Internet
Author: User

Write your own template parser

Because recently in the study arttemplate,ejs,baaidutemplate and so on template, so, on a whim, oneself also wrote a simple template parser.

One of the most basic template parsers, what functions do you need?

    1. Reading variable values
    2. Parsing template Statements

Following this idea, we write a simple parser with the following requirements:

    1. Read value: <%= variable name%>
    2. Statement support: <% if (type = = 1) {%> good! <%}%>

Overall, if the template is as follows:

我叫:<%= name %><br/><% if(type == 1){ %>    <%= type %><% } %>

If you have data {name: ' da bear ' type:1}, you need to output:

我叫: da宗熊状态: good!

What do we need to do according to the above requirements? Because the script is executed within the template, the most straightforward approach is to translate the template into JavaScript.

Hands-on variables

Looking at the code of several template engines above, the main idea is:

    1. Find the ' <%...%> ' module and process it with regular matching
    2. Stitch everything that matches out into a string
    3. The executable function is then generated through the new function

But 3, for the <%= variable%> value, has different processing:

EJS assigns a variable access context to a variable through the WITH statement.

Arttemplate and Baidutemplate generate variable declaration statements by iterating through the passed variables, thus achieving the effect of assigning values to variables.

Taking into account the inefficiency of the WITH statement, the second form is taken here.

// 如有传入的变量参数为:datavar data = {    ‘da宗熊‘1};// 那模板中,遍历变量,生成声明语句var‘‘;for(varin data){    ‘var ‘ + name +‘ = data.‘‘;‘;}// varStatement = ‘var name = data.name;var type = data.type;‘;
Function

The second and most important, MO is the statement of the parsing template.

Because the template is often the innerhtml of an element, and it wraps [well, I'm not good at controlling], I usually replace it:

<!--If you have a template --<script id="template" type="Html/template">My name is:<%= name%> <br/><% if(type = = 1) { %> Status: <%= type%><%}%>          </script><script> var html = template.innerhtml; //Replace swap line: HTML = html.replace (/\s/g, "");    </script>

Taking into account that the 'xx content <% expression%> ' This form is more useful for regular matching, so, the ' front content <% expression %> the ' front ' and ' Back ' section of the following:

//ResList is the final result, Rightcontent is the contents of the ' Back ' section  var  reslist = [], rightcontent = " ; html = html.replace (/(. *?) (<%.*%>) (. *)/g , function   (str, left, center, right)     { rightcontent = right;    Reslist.push (left);    Console.log ( "left:%s center:%s right:%s" , left, center, right); return  Center;}); //a regular match will be:  //Left: My name is:  //Center: <%= name%> <br/> <% if (type = = 1) {%> status: <%= type% > <%}%>  //right:   

The rest of the ' center ' content conforms to the 'xx content <% expression%> ' format, so, using regular, compile the remainder of the content:

var__tmp_list__ =' __tmp_list__ ', __tmp_data__ =' __tmp_data__ ';//Dynamic function content that needs to be compiledvarFnstr ="';//Start match expression, match ' xxx<% expr%> 'Html.replace (/(.*?) <% (. *?) %>/g, function(str, HTML, exp){Console.log ("html:%s exp:%s", HTML, exp);//HTML contentFnstr + = __tmp_list__ +". Push ('"+ QUOTE (HTML) +"');";//expression content, with equal sign, value, without, is the logical control part of the dynamic function    if(Exp.indexof ("=") ===0) {Fnstr + = __tmp_list__ +". Push ("+ Exp.slice (1) +");"; }Else{FNSTR + = exp; }});
Generating dynamic functions

The preparation is complete and the final step remains:

// 构建编译的动态函数varnewFunction(__TMP_DATA__, __TMP_LIST__, fnStr);// 如果结果列表没有数据,则没有需要编译的内容if0){    // 把需要编译的数据,结果列表,传入动态函数    fn(data, resList);    // 不要漏了最后一个小尾巴,上面去除 ‘前’ 和 ‘后’部分,留下的    resList.push(rightContent);    console.log(resList.join(""));}else{    console.log(html);}

A simple template compiler function, has been done ~.

At last

The most apart version, there must be a lot of bugs, but the idea should not be wrong. There are a lot of expansion, such as escaping, error detection, configuration of the delimiter or something, you can try, here is no longer detailed introduction.

Full code
<! DOCTYPE html><html><head>    <meta charset="Utf-8" />    <title></title></head><body>    <div id="Content"></div></body><script id="template" type="Html/template"><%= title%></H1><% if(type = = 1) {%> <pclass="123">   Status: <%= status%></p ><%}%> xx..                  </script><script> function trim(str){    returnStr.replace (/^\s*|\s*$/g,"");}//Transfer ' and ' function quote(str){    returnStr.replace (/(' | ') /g,' \\$1 ');}varHTML = template.innerhtml data = {title:"da Zong Xiong", type:1, Status:"Very good"};//Dynamic function with a single parametervar__tmp_data__ =' __tmp_data__ ', __tmp_list__ =' __tmp_list__ ';//Result list, dynamic function stringvarReslist = [], fnstr ="', rightcontent ="';//Remove line breakshtml = Html.replace (/\s/g," ");//Because ' xx content <% expression%> ' This form compares well with the regular match, therefore, the ' front content <% expression%> behind ' the ' front ' and ' behind ' to removehtml = Html.replace (/(.*?) (<%.*%>) (. *)/g, function(str, left, center, right){Rightcontent = right;    Reslist.push (left); Console.log ("left:%s center:%s right:%s", left, center, right);returnCenter;});//Start match expressionHtml.replace (/(.*?) <% (. *?) %>/g, function(str, HTML, exp){Console.log ("html:%s exp:%s", HTML, exp);//HTML contentFnstr + = __tmp_list__ +". Push ('"+ QUOTE (HTML) +"');";//Expression content    if(Exp.indexof ("=") ===0) {Fnstr + = __tmp_list__ +". Push ("+ Exp.slice (1) +");"; }Else{FNSTR + = exp; }});//Build variable definitionvarVarstatement =""; for(varNameinchData) {varstatement + =' var '+ name +' =__tmp_data__. '+ name +'; ';} Fnstr = varstatement + fnstr;//Build a compilation functionvarfn =New Function(__tmp_data__, __tmp_list__, FNSTR);if(Reslist.length >0) {fn (data, reslist);    Reslist.push (rightcontent); Console.log (Reslist.join (""));}Else{console.log (HTML);}</script></html>

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

JavaScript to write your own template parser

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.