Basic Implementation Method of JavaScript template engine, javascript Template

Source: Internet
Author: User

Basic Implementation Method of JavaScript template engine, javascript Template

The template separates data from presentation, making the presentation logic and effect easier to maintain. Build an extremely simple template conversion engine step by step using javascript Function objects

Template Introduction
A template usually refers to the text embedded with some dynamic programming language code. The combination of data and templates can change different results. Templates are usually used to define the display form, which makes data presentation richer and easier to maintain. For example, the following is an example of a template:

<ul> <% for(var i in items){ %> <li class='<%= items[i].status %>'><%= items[i].text %></li> <% } %></ul>

If the following items data exists:

items:[ { text: 'text1' ,status:'done' }, { text: 'text2' ,status:'pending' }, { text: 'text3' ,status:'pending' }, { text: 'text4' ,status:'processing' }]

In some way, the following Html code can be generated:

<ul> <li class='done'>text1<li> <li class='pending'>text2<li> <li class='pending'>text3<li> <li class='processing'>text4<li></ul>

If you do not use a template and want to achieve the same effect, to display the above data as the result, you need to do the following:

var temp = '<ul>';for(var i in items){ temp += "<li class='" + items[i].status + "'>" + items[i].text + "</li>";}temp += '</ul>';

It can be seen that using templates has the following advantages:

Simplified html writing
Through programming elements (such as loops and condition branches), data presentation is more controllable
Data and presentation are separated to make the presentation logic and effect easier to maintain.
Template engine
By analyzing templates, the program that combines data and templates to output the final result is called the template engine. There are many templates, and there are also many corresponding template engines. An old template called ERB is used in many web frameworks, such as ASP. NET and Rails... The above example is the example of ERB. Two core concepts in ERB: evaluate and interpolate. On the surface, evaluate refers to the part contained in <%>, and interpolate refers to the part included in <% = %>. From the perspective of the template engine, the part in evaluate is not directly output to the result, which is generally used for process control. The part in interpolate is directly output to the result.

The implementation of the template engine depends on the dynamic compilation or Interpretation Features of the programming language to simplify implementation and improve performance. For example, ASP. NET uses the dynamic compilation of. NET to compile the Template into a dynamic class and reflect the code in the dynamic execution class. This implementation is actually complicated, because C # Is a static programming language, but javascript can use functions to implement a simple template engine with very little code. This article implements a simple ERB template engine to show the strength of javascript.

Template text Conversion
For the above example, review the differences between using a template and not using a template:

Template syntax:

<ul> <% for(var i in items){ %> <li class='<%= items[i].status %>'><%= items[i].text %></li> <% } %></ul>

Non-template syntax:

var temp = '<ul>';for(var i in items){ temp += "<li class='" + items[i].status + "'>" + items[i].text + "</li>";}temp += '</ul>';

Observe carefully. In fact, these two methods are very similar and can find a one-to-one correspondence in a certain sense. If you can convert the template text into code execution, you can implement template conversion. There are two principles in the conversion process:

Directly concatenate common text into strings
Interpolate (that is, <% = %>) is used to concatenate the content into a string as a variable.
If you encounter evaluate (that is, <%>), directly use it as the code
Convert the above example according to the above principles and add a total function:

Var template = function (items) {var temp = ''; // start to convert temp + = '<ul>'; for (var I in items) {temp + = "<li class = '" + items [I]. status + "'>" + items [I]. text + "</li>" ;}temp + = '</ul> ';}

Finally, execute this function and pass in the data parameters:

var result = template(items);

Javascript dynamic Functions
It can be seen that the above conversion logic is actually very simple, but the key issue is that the template is changed, which means that the generated program code must also be generated and executed at runtime. Fortunately, javascript has many dynamic features, one of which is Function. We usually use the function keyword to declare a Function in js, and rarely use a function. In JavaScript, function is a literal syntax. When Javascript is run, the literal function is converted into a Function object. In fact, Function provides a more underlying and flexible mechanism.

The syntax for directly creating a Function using the Function class is as follows:

var function_name = new Function(arg1, arg2, ..., argN, function_body)

For example:

// Create a dynamic Function var sayHi = new Function ("sName", "sMessage", "alert (\" Hello \ "+ sName + sMessage );"); // execute sayHi ('hello', 'World ');

Function bodies and parameters can be created using strings! So cool! With this feature, you can convert the template text to the string of the function body, so that you can create dynamic functions for dynamic calls.

Implementation
First, use the regular expression to describe interpolate and evaluate. Parentheses are used for grouping and capturing:

var interpolate_reg = /<%=([\s\S]+?)%>/g;var evaluate_reg = /<%([\s\S]+?)%>/g;

These two regular expressions are merged for continuous matching of the entire template. However, note that all strings matching interpolate can match evaluate, so interpolate requires a higher priority:

var matcher = /<%=([\s\S]+?)%>|<%([\s\S]+?)%>/g

Design a function to convert the template. The input parameter is the template text string and data object.

Var matcher =/<% = ([\ s \ S] + ?) %> | <% ([\ S \ S] + ?) %>/G // text: input template text string // data: data Object var template = function (text, data ){...}

Use the replace method to perform regular expression matching and "Replacement". In fact, our goal is not to replace interpolate or evaluate, but to build a "method body" during the matching process ":

Var matcher =/<% = ([\ s \ S] + ?) %> | <% ([\ S \ S] + ?) %>/G // text: input template text string // data: data Object var template = function (text, data) {var index = 0; // record where var function_body = "var temp =''; "; function_body + =" temp + = '"; text. replace (matcher, function (match, interpolate, evaluate, offset) {// after finding the first match, use the previous part as the regular String concatenation expression function_body + = text. slice (index, offset); // if it is <%... %> directly serves as a code snippet. evaluate is the captured group if (evaluate) {function_body + = "';" + evaluate + "temp + = '";} // if it is <% =... %> concatenate a string. interpolate is the captured group if (interpolate) {function_body + = "'+" + interpolate + "+'";} // increments the index, skip evaluate or interpolate index = offset + match. length; // The return here is meaningless, because the key is not to replace text, but to build function_body return match ;}); // The final code should be to return temp function_body + = "'; return temp ;";}

At this point, function_body is a string, but the content is actually a piece of function code. You can use this variable to dynamically create a function object and call it through the data parameter:

var render = new Function('obj', function_body);return render(data);

In this way, render is a method that can be called. The code inside the method is constructed by the template content, but the general framework should be like this:

function render(obj){ var temp = ''; temp += ... ... return temp;}

Note that the method parameter is obj, so the variable referenced in the template should be obj:

<script id='template' type='javascript/template'> <ul> <% for(var i in obj){ %>  <li class="<%= obj[i].status %>"><%= obj[i].text %></li> <% } %> </ul></script>

It seems OK, but there is a problem that must be solved. The template text may contain characters such as \ r \ n \ u2028 \ u2029. If these characters appear in the code, an error occurs. For example, the following code is incorrect:

temp += ' <ul> ' + ... ;

We want to see the following code:

temp += '\n \t\t<ul>\n' + ...;

In this case, the \ above \ n must be converted to \, and finally to \ n.

Another problem is that the above Code cannot splice the part after the last evaluate or interpolate. The solution to this problem is also very simple, you only need to add a match at the end of the line in the regular expression:

var matcher = /<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$/g;

Relatively complete code

Var matcher =/<% = ([\ s \ S] + ?) %> | <% ([\ S \ S] + ?) %> | $/G // special character escape processing in template text var escaper =/\\| '| \ r | \ n | \ t | \ u2028 | \ u2029/g; var escapes = {"'": "'", '\': '\', '\ R': 'R',' \ N': 'n ', '\ t': 'T',' \ u2028 ': 'u2028',' \ u2029 ': 'u2029'}; // text: input template text string // data: data Object var template = function (text, data) {var index = 0; // record where var function_body = "var temp =''; "; function_body + =" temp + = '"; text. replace (matcher, function (match, interpolate, evaluate, offset) {// after the first match is found, use the previous part as the expression for splicing a common string // Add the Escape Character function_body + = text. slice (index, offset ). replace (escaper, function (match) {return '\' + escapes [match];}); // if it is <%... %> directly serves as a code snippet. evaluate is the captured group if (evaluate) {function_body + = "';" + evaluate + "temp + = '";} // if it is <% =... %> concatenate a string. interpolate is the captured group if (interpolate) {function_body + = "'+" + interpolate + "+'";} // increments the index, skip evaluate or interpolate index = offset + match. length; // The return here is meaningless, because the key is not to replace text, but to build function_body return match ;}); // The final code should be to return temp function_body + = "'; return temp;"; var render = new Function ('obj', function_body); return render (data );}

The call code can be as follows:

<script id='template' type='javascript/template'> <ul> <% for(var i in obj){ %>  <li class="<%= obj[i].status %>"><%= obj[i].text %></li> <% } %> </ul></script>...var text = document.getElementById('template').innerHTML;var items = [ { text: 'text1' ,status:'done' }, { text: 'text2' ,status:'pending' }, { text: 'text3' ,status:'pending' }, { text: 'text4' ,status:'processing' }];console.log(template(text,items));

It can be seen that we have implemented a simple template with only a small amount of code.

Legacy problems
Note the following details:

  • Because <% or %> are the boundary characters of the template, if the template needs to output <% or %>, You need to design an escape method.
  • If the data object contains null, you obviously do not want to output 'null'. Therefore, you need to consider null in the code of function_body.
  • It may be inconvenient to reference data using the obj parameter each time in the template. You can add with (obj | |{}) {...} In function_body {}){...}, in this way, you can directly use the obj attribute in the template.
  • You can design to return the render instead of the converted result, so that the generated functions can be cached externally to improve performance.
Articles you may be interested in:
  • Explore how to use the Javascript template engine mustache. js
  • Details about the Javascript template engine mustache. js
  • Example of JavaScript template engine usage
  • How to use javascript to write a simple page template engine
  • Node. js is suffixed with. html when the ejstemplate is used.
  • Introduction to common JavaScript template Engines
  • Simple Introduction to simple js template engine
  • High-performance JavaScript template engine implementation principles
  • Laytpl exquisite and clever JavaScript template engine
  • PHP's solution to conflicts with CSS/JSON in conventional template Engines
  • Javascript lightweight template engine juicer User Guide

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.