JavaScript template engine Development instance

Source: Internet
Author: User
Tags bind join regular expression


With the popularity of Nodejs, JavaScript has become popular both at the front end and back end. There are many mature JavaScript template engines, such as Swig, that can be used both on the back end and on the front end.

But most of the time, the front-end template simply needs to create an HTML fragment, with Swig this full-featured template is a bit overqualified. We're trying to write a simple front-end template engine for ourselves, and it's not really complicated.

Before writing the front-end template engine code, we should think about how to invoke it, that is, what the interface of the template engine should be. We want to call it this way:

Create a template engine:

var tpl = new Template (' <p>today: {date}</p>\n<a href= '/{user.id|safe} ' >{ Any}</a> ');

Render HTML fragment:

var model = {

date:20150316,

User: {

id: ' a-000&001 ',

comp Any: ' At&t '

}

;

var html = tpl.render (model);

Console.log (HTML);

<p>Today:20150316</p>

//<a href= "/a-000&001" >AT&amp; T</a>

As a result, a template engine is done by replacing the variable in a string with the model variable.

Like Swig, a Jinja2 template engine, it can replace variables such as {{Model.prop}}}.

We use {Model.prop} to implement our own variable substitution, the basic idea is to use a regular expression to match {xxx.xxx}:

var re =/\{\s* ([a-za-z\.\_0-9 ()]+) \s*\}/m

var match = re.exec (' A {template} string ');

If a positive match succeeds, then match is not empty, match[0] is the matched string {Template},match[1] is the captured variable template,match.index is the matching index.

As long as the constant match to the variable, and then replace with the model's content, you can get the final HTML. However, it is not easy to analyze user.addr.zipcode and then go to the model to find it. Also, the template should be precompiled so that subsequent rendering will be fast.

JavaScript allows you to use the new function (' source ') to create a function from a string, which is exactly the same as the function we defined with functions (), so a template engine's compilation process is to create a function, The function is then called to implement the template rendering.

The function code that needs to be compiled should look like this:

function () {

var r = [];

R.push (' <p>today: ');

R.push (this.date);

R.push (' </p>\n<a href= "/);

R.push (this.user.id);

R.push (' > ');

R.push (this.user.company);

R.push (' </a> ');

Return R.join (");

}

Note that the variable name changed from Variable.prop to This.variable.prop because we would bind the model to the this variable when we called the function.

Therefore, the code for the template engine is as follows:

Function template (TPL)  {    var          FN,         match,         code  = [' var r=[]; '],         re = /\{\s* ([a-zA-Z\ . \_0-9 ()]+) \s*\}/m,         addLine = function  (text)  {            code.push (' R.push '  +

 text.replace (/\ '/g,  ' \\\ '). Replace (/\n/g,  ' \\n '). Replace (/\r/g,  ' \ R ')  +  ');

        };     while  (Match = re.exec (TPL))  {         if  (match.index > 0)  {             addline (Tpl.slice (0, match.inDEX)); &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP}         code.push (' R.push (this. '

 + match[1] +  ');         tpl = tpl.substring (Match.index + match[0]

. length);

&NBSP;&NBSP;&NBSP;&NBSP}     addline (TPL);

    code.push (' Return r.join (\ '); ');     //  Create function:     fn = new function (code.join (' \ n '))

;     //  call the function with render () and bind this parameter:     this.render = 

function  (model)  {        return fn.apply (model);

    }; }

Now, this simple template engine is ready to work. But there are a few small problems to solve, one is that the default variable should be HTML escaped when replaced, and second, if you do not need to escape the variable, you can use an expression such as {User.id|safe} to express user.id without escaping.

The final code processed through HTML escape and {Variable|safe} is as follows:

Function template (TPL)  {    var          FN,         match,         code  = [' var r=[];\nvar _html = function  (str)  { return  Str.replace (/&/g, \ ' &amp;\ '). Replace (/"/g, \ ' &quot;\ '). Replace (/\ '/g, \ ' & #39; \ ' ). Replace (/</g, \ ' &lt;\ '). Replace (/>/g, \ ' &gt;\ '); }; '],          re = /\{\s* ([A-za-z\.\_0-9 ()]+) (\s*\|\s*safe)? \s*\}/m,          addLine = function  (text)  {             code.push (' R.push '  + text.replace (/\ '/g,  ' \\\ ').

Replace (/\n/g,  ' \\n '). Replace (/\r/g,  ' \ \ r ')  +  ');         };     while  (Match = re.exec (TPL))  {         if  (match.index > 0)  {        

    addline (Tpl.slice (0, match.index)); &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP}         if  ( MATCH[2])  {            code.push (' R.push ( String (this. '

 + match[1] +  ');

        }         else {             code.push (' R.push (_html String (this.

 + match[1] +  '));         }         tpl =

 tpl.substring (match.index + match[0].length); &nbSP;&NBSP;&NBSP;&NBSP}     addline (TPL);

    code.push (' Return r.join (\ '); ');

    fn = new function (Code.join (' \ n '));     this.render = function  (model)  {     

   return fn.apply (model);

    }; }

Now we can use this template engine with our preset code. However, it is not a good idea to write a template in a string. The best solution is to use <script> tags, write the template inside, note must add Type= "Text/plain":

<script id= "TPL" type= "Text/plain" >
<p>today: {date}</p> <a "href=/{
}" ">{user.company}</a>
</script>
Then, use jquery to get the template content and render it:
var tpl = new Template ($ (' #tpl '). HTML ());
var s = tpl.render ({
date:20150101,
User: {
id: ' a-000&001 ', company
: ' at ; T '
}
});
$ (' #other '). HTML (s);

In this way, we've implemented a simple JavaScript template engine with less than 30 lines of code.

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.