Details about the Javascript template engine mustache. js and mustache template engine

Source: Internet
Author: User

Details about the Javascript template engine mustache. js and mustache template engine

This article summarizes its usage methods and some usage experiences. The content is not very advanced. It is purely an entry-level content. Just take a look. However, if you have not used such a javascript Engine library, this article is worth reading. I believe that after you understand its powerful functions and simple usage, you can't wait to use it for your work.

1. Start with a simple and realistic demand
At present, the company has developed a unified development platform. The backend encapsulates the MVC interface and the interface for adding, deleting, modifying, and querying data, I developed a development framework using bootstrap + hand-writing components on the front end. With CAS integrated, I first developed a unified permission management system based on CAS, this system is the first subsystem of our development platform. It is used to manage and configure the menus and authorizations of all subsystems and to manage the organization structure and users of the entire company, later, we developed business system A and business system B. Since these three subsystems correspond to three java projects, three applications are deployed in tomcat during the final deployment. One requirement is:

  • 1) After logging on to each system, click the system name. A drop-down menu is displayed, showing all subsystems with permissions;
  • 2) then, you can click another subsystem to switch to the selected system. After arriving at other systems, you can also switch back from the system because the drop-down menu is made;
  • 3) if the user has only one system permission, no drop-down menu is displayed.

The requirement is actually quite simple. The prototype is probably like this:

The function is implemented by calling the interface for obtaining the system list after logging on to each subsystem and rendering a drop-down menu in js. The format returned by this interface is:

Data: [{"sortOrder": 1, "isCurrent": true, "systemHttpUrl": "http: // xxxx: 8080/permission", "systemName ": "unified permission management system" },{ "sortOrder": 2, "isCurrent": false, "systemHttpUrl": "http: // xxxx: 8080/systemA ", "systemName": "business system A" },{ "sortOrder": 3, "isCurrent": false, "systemHttpUrl": "http: // xxxx: 8080/systemB ", "systemName": "Business System B"}]

If we do not use the template engine, the traditional method to parse the data and convert it into an html string is usually:

Function data2Html (data) {data = data | []; var html = ['<ul class = "nav navbar-left nav-system"> ', '<li class = "dropdown">', '<a href = "javascript :; "class =" dropdown-toggle "data-toggle =" dropdown "title =" Switching System "> '], l = data. length; if (l <2) {l = 1 & html. push (data [0]. systemName | ''); html. push ('</a> </li> </ul>'); return html. join ('');} var curSysAry = data. filter (function (s) {return s. isCurrent;}); html. push (curSysAry [0]. systemName + '<I class = "fa-caret-down"> </I> </a> <ul class = "dropdown-menu">'); data. sort (function (a, B) {return. sortOrder-B. sortOrder;}); for (var I = 0; I <l; I ++) {I & html. push ('<li role = "separator" class = "divider"> </li>'); html. push ('<li> <a href = "' + data [I]. systemHttpUrl + '"target =" _ self ">' + data [I]. systemName + '</a> </li>');} html. push ('</ul> </li> </ul>'); return html. join ('');}

This String concatenation method has many drawbacks:

  • 1) difficult, especially complicated splicing logic. The splicing string is long;
  • 2) It is not easy to maintain. If you do not care about it, the corresponding relationship of the tag will be wrong;
  • 3) The structure is unclear.

The tool that can simplify this scenario is the template engine, which is the first Technology backend in the template engine. If you have used jsp, you must know that jsp is a template used to parse and present data, other background template engines include velocity and freemarker. There are also many front-end template engines. mustache. js is a popular one, and git has over 8000 likes. If we use mustache. js to solve this problem, we can turn it into this:

// Define the template var _ template = ['<ul class = "nav navbar-left nav-system">' based on the tag corresponding to the attribute name ', '<li class = "dropdown">', '<a href = "javascript :; "class =" dropdown-toggle "data-toggle =" dropdown "title =" Switching System "> ', '{{ curSystemName }}{{# multiple }}< I class = "fa-caret-down"> </I >{{/ multiple }}', '</a>', '{{# multiple }}< ul class = "dropdown-menu">', '{{# systems }}', '{^ first }}< li role = "separator" class = "div Ider "> </li >{{/first} ',' <li> ', '<a href = "{systemHttpUrl }}" target =" _ self ">{{ systemName }}</a>', '</li> ', '{/systems}', '</ul> {/multiple}', '</li>', '</ul>']. join (''); // initialize the Mustache template. parse (_ template); function data2Html (data) {data = data | []; var curSysAry = data. filter (function (s) {return s. isCurrent;}); data. sort (function (a, B) {return. sortOrder-B. sortOrder;}); data = data. Map (function (s, I) {s. first = I = 0; return s}); // The template is rendered as a string return Mustache. render (_ template, {curSystemName: curSysAry. length? CurSysAry [0]. systemName: '', multiple :!! Data. length, systems: data });}

Comparing the two codes, we will find the following code, which has the following advantages over the previous one:

  • 1) The structure is clear. All html to be rendered are defined in one position without any splicing;
  • 2) The logic is clear. The tags in the template actually correspond to the attribute names of the objects passed in during template rendering;
  • 3) easy to maintain. To add or delete tags, you only need to adjust the array corresponding to the template.

Through this example, we should be able to have a general understanding of the template engine. Such tools are becoming more and more common in front-end development, especially for front-end and back-end separation applications, it is already the content of the basic architecture of such applications. Mustache. js is a very easy-to-use engine implementation. The following content will introduce the commonly used template configurations of this tool and use them with practical examples. I hope you will like this tool more :)

2. Usage of mustache
The usage of mustache is very simple. first introduce its js file through the script tag, and then perform the following operations:
1) define the template string
There are two ways to define a template. The first method is as shown in the previous section. You can directly use [...]. the join ('') method is defined in js Code. method 2 defines the template content in html using a script:

<script id="tpl" type="text/html"> Hello {{name}}!</script>

Before compiling the template, get the innerHTML of tpl to define the original template string:

var tpl = document.getElementById('tpl').innerHTML.trim();

For details about how to define a template, refer to the following suggestions:
If this template is used for multiple pages, we recommend that you define the template in js Code. If this template is only used for the current page, we recommend that you directly define it in the script tag to facilitate management.
2) pre-compiled Template
Assuming that the original template string has been defined and referenced with the tpl variable, you can use the following code to pre-compile the template:

Mustache.parse(tpl);

It should be noted that after pre-compilation, tpl is no longer the original template string, and even the data type is changed to the array type, which is the result of pre-compilation.
3) Rendering Template
The rendering method is simple:

var htmlAfterRendered = Mustache.render(tpl1, obj);

Obj references a data source object. mustache replaces the attribute tags in the template with the object content according to the agreed rules. HtmlAfterRendered is the replaced string. You can use it to complete the DOM operation you need.

3. The idea of mustache
The core of mustache is tag and logic-less. You can see from the previous code that the tag {name} is used when the template is defined, and the tag {# systems }}{{/systems} is also used }}, this is the mustache tag, but it replaces <> with {} to avoid confusion with <> of html tags. Logic-less, which can be translated into light logic, because if-else is not used when defining a template, and there is no circular encoding. tags are used to solve all problems. Its labels are very simple, however, after reading this article, you will be surprised to find that you can solve almost all the problems by using the following labels:
{Prop }}
{{{ Prop }}}
{{# Prop }}{{/prop }}
{^ Prop }}{{/prop }}

4. {prop} tag
This label is the most commonly used in the mustache template. You can convert the value corresponding to the prop attribute on the data source object into a string for output. The following is the same attribute, corresponding to different types of values, test of the output results after mustache rendering (the front and back of the dash are used to make the rendering results of this label clearer ):

<Script id = "tpl1" type = "text/html">-{prop }}- </script> <script> var tpl1 = document. getElementById ('tpl1 '). innerHTML. trim (); Mustache. parse (tpl1); // test the falsy value console. log (Mustache. render (tpl1, {prop: ''}); // -- console. log (Mustache. render (tpl1, {prop: 0}); //-0-console. log (Mustache. render (tpl1, {prop: null}); // -- console. log (Mustache. render (tpl1, {prop: undefined}); // -- console. log (Mustache. render (tpl1, {prop: false}); //-false-console. log (Mustache. render (tpl1, {prop: NaN}); //-NaN-// test the simple object console. log (Mustache. render (tpl1, {prop: {name: 'jason '}); //-[object Object]-// test the array console. log (Mustache. render (tpl1, {prop: [{name: 'jason '}, {name: 'frank'}]}); //-[object Object], [object Object]-// test date object console. log (Mustache. render (tpl1, {prop: new Date ()}); //-Mon Jan 18 2016 15:38:46 GMT + 0800 (China Standard Time) -// test the simple object var obj1 = {name: 'jason '} of the custom toString; obj1.toString = function () {return this. name;}; console. log (Mustache. render (tpl1, {prop: obj1}); //-jason-// test boolean number string console. log (Mustache. render (tpl1, {prop: true}); //-true-console. log (Mustache. render (tpl1, {prop: 1.2}); //-1.2-console. log (Mustache. render (tpl1, {prop: 'yes'}); //-yes-// test function console. log (Mustache. render (tpl1, {prop: function () {}}); // -- console. log (Mustache. render (tpl1, {prop: function () {return 'it \'s a fun '}); //-it's a fun-console. log (Mustache. render (tpl1, {prop: function () {return false ;}}); //-false-console. log (Mustache. render (tpl1, {prop: function () {return function (text, render) {return "<B>" + render (text) + "</B>" };}}); //-function (text, render) {// return "<B>" + render (text) + "</B>" //}-</script>

The logic of mustache rendering {prop} labels is:

  • 1) if the value referenced by prop is null or undefined, it is rendered as an empty string;
  • 2) If prop references a function, the function is automatically executed during rendering and the return value of the function is used as the rendering result. If the return value is null or undefined, the rendering result is still a blank string; otherwise, the returned value is converted to a string as the rendering result (pay attention to the last use case and render the Function Code directly );
  • 3) In other scenarios, directly convert the value referenced by prop into a string as the rendering result.

By default, mustache performs url encoding or html encoding on the original values of prop before rendering prop. Therefore, there is a Use Case rendering result, converts an English single quotation mark into an html Entity character:

console.log(Mustache.render(tpl1, {  prop: function () {   return 'it\'s a fun'  }}));//-it's a fun-

To prevent this encoding behavior, you only need to change the tag format to {prop:

<script id="tpl1" type="text/html"> -{{{prop}}}-</script>console.log(Mustache.render(tpl1, { prop: function () {  return 'it\'s a fun' }}));//-it's a fun-

5. {# prop }}{{/prop} tag
This is very powerful for labels, and can complete the if-else, for-each and dynamic rendering template functions at the same time. Other template contents can be defined between these tags and all tags can be nested. Next, let's take a look at how mustache uses this pair of tags to complete these three template functions.

1) if-else Rendering

Only the prop attribute exists on the data source object and is not a falsy value (six falsy values in javascript: null, undefined, NaN, 0, false, null string ), if the array is not empty, the content between labels will be rendered; otherwise, the content will not be rendered:

<Script id = "tpl2" type = "text/html">-{{# prop }}content {{/ prop }}- </script> <script> var tpl2 = document. getElementById ('tpl2 '). innerHTML. trim (); Mustache. parse (tpl2); // test the falsy value console. log (Mustache. render (tpl2, {prop: ''}); // -- console. log (Mustache. render (tpl2, {prop: 0}); // -- console. log (Mustache. render (tpl2, {prop: null}); // -- console. log (Mustache. render (tpl2, {prop: undefined}); // -- console. log (Mustache. render (tpl2, {prop: false}); // -- console. log (Mustache. render (tpl2, {prop: NaN}); // -- // test the empty array console. log (Mustache. render (tpl2, {prop: []}); // -- // test the property console that does not exist. log (Mustache. render (tpl2, {prop2: true}); // -- // test function console. log (Mustache. render (tpl2, {prop: function () {}}); // -- console. log (Mustache. render (tpl2, {prop: function () {return false ;}}); // -- console. log (Mustache. render (tpl2, {prop: function () {return [] ;}}); // -- // test the console of a simple object. log (Mustache. render (tpl2, {prop: {name: 'jason '}); //-content-// test date object console. log (Mustache. render (tpl2, {prop: new Date ()}); //-content-// test boolean number string console. log (Mustache. render (tpl2, {prop: true}); //-content-console. log (Mustache. render (tpl2, {prop: 1.2}); //-content-console. log (Mustache. render (tpl2, {prop: 'yes'}); //-content-// test the function console that returns a non-falsy, non-empty array. log (Mustache. render (tpl2, {prop: function () {return 'it \'s a fun '}); //-content-</script>

The special point in the above case is that when the prop property references a function, {# prop} will automatically call this function, the Return Value of the function is used as the basis for determining the if-else rendering logic. That is to say, if the function returns a falsy value or an empty array, the content between tags will not be displayed.

2) for-each Rendering

When the prop attribute references a non-empty array, the content between the tags is iterated according to the array size, and when the array element is an object, this object will also be used as the context of each iteration, so that the tag during iteration can directly reference the attribute on the array element:

<script id="tpl2" type="text/html"> -{{#prop}}{{name}},{{/prop}}-</script><script>  var tpl2 = document.getElementById('tpl2').innerHTML.trim();  Mustache.parse(tpl2);  console.log(Mustache.render(tpl2, {prop: [{name: 'jason'}, {name: 'frank'}]}));//-jason,frank,-</script>

The test results show that the template content between {# prop }}{{/prop} iterates twice according to the array referenced by prop, in addition, the {name} tag is used inside the tag to output the value corresponding to the name attribute of the array element object.

If the prop property references a function, but the return value of this function is an array type, the for-each rendering will still be performed:

<script id="tpl2" type="text/html"> -{{#prop}}{{name}},{{/prop}}-</script><script>  var tpl2 = document.getElementById('tpl2').innerHTML.trim();  Mustache.parse(tpl2);  console.log(Mustache.render(tpl2, {   prop: function(){    return [{name: 'jason'}, {name: 'frank'}];   }  }));//-jason,frank,-</script>

3) Dynamic Rendering

When the prop property references a function and the return value of this function is still a function, mustache will call the returned function again and pass two parameters to it: text indicates the content of the original template, and render indicates the object for executing rendering in mustache, so that the render object can be used inside the function to customize the rendering logic based on the original template content, the Return Value of the function is used as the rendering result (the rendering logic of this return value is exactly the same as that of the {prop} tag ):

<script id="tpl2" type="text/html"> -{{#prop}}content{{/prop}}-</script><script>  var tpl2 = document.getElementById('tpl2').innerHTML.trim();  Mustache.parse(tpl2);  console.log(Mustache.render(tpl2, {  prop: function(){   return function (text, render) {    return "<b>" + render(text) + "</b>"   };  } }));//-<b>content</b>-</script>

6. {^ prop }}{{/prop} tag
This pair of labels, opposite to the if-else rendering execution logic of {# prop }}{{/prop}, that is, only when the prop property does not exist, or, when a falsy value is referenced, or an empty array, the content between tags is displayed. Otherwise, the content is not displayed:

<Script id = "tpl2" type = "text/html">-{^ prop} content {/prop}-</script> <script> var tpl2 = document. getElementById ('tpl2 '). innerHTML. trim (); Mustache. parse (tpl2); // test the falsy value console. log (Mustache. render (tpl2, {prop: ''}); //-content-console. log (Mustache. render (tpl2, {prop: 0}); //-content-console. log (Mustache. render (tpl2, {prop: null}); //-content-console. log (Mustache. render (tpl2, {prop: undefined}); //-content-console. log (Mustache. render (tpl2, {prop: false}); //-content-console. log (Mustache. render (tpl2, {prop: NaN}); //-content-// test the empty array console. log (Mustache. render (tpl2, {prop: []}); //-content-// test the property console that does not exist. log (Mustache. render (tpl2, {prop2: true}); //-content-// test function console. log (Mustache. render (tpl2, {prop: function () {}}); //-content-console. log (Mustache. render (tpl2, {prop: function () {return false ;}}); //-content-console. log (Mustache. render (tpl2, {prop: function () {return [] ;}}); //-content-// test the console of a simple object. log (Mustache. render (tpl2, {prop: {name: 'jason '}); // -- // test date object console. log (Mustache. render (tpl2, {prop: new Date ()}); // -- // test the non-empty array console. log (Mustache. render (tpl2, {prop: [{name: 'jason '}, {name: 'Tom'}]}); // -- // test the boolean number string console. log (Mustache. render (tpl2, {prop: true}); // -- console. log (Mustache. render (tpl2, {prop: 1.2}); // -- console. log (Mustache. render (tpl2, {prop: 'yes'}); // -- // test the function console that returns a non-falsy, non-empty array. log (Mustache. render (tpl2, {prop: function () {return 'it \'s a fun '}); // -- // test the function console that returns the function. log (Mustache. render (tpl2, {prop: function () {return function (text, render) {return '<B>' + render (text) + '</B>' }})); // -- </script>

7. rendering context
Mustache has a rendering context stack concept. At the beginning of template rendering, the data source object is used as the current rendering context and pushed into the context stack. When the {# prop} tag is encountered, if prop references an object, an array of non-empty objects, or prop references a function, in addition, if this function returns an object or an array of non-empty objects, the elements of this object or array will be used as the current rendering context and pushed to the context stack, when the label is rendered, the context is displayed to restore the context used by the previous label. The {# prop} tag can be nested in multiple layers. Therefore, multiple layers of context exist during template rendering. When parsing tags, mustache searches for whether the current context object has this attribute based on the tag name. If it does not exist, it searches for the upper-level context object, as long as it is found at a certain layer, the layer context object value is used for rendering.

<script id="tpl2" type="text/html"> -{{#person}}{{#student}}{{#address}}address: {{home}},age: {{age}}{{/address}}{{/student}}{{/person}}-</script><script> var tpl2 = document.getElementById('tpl2').innerHTML.trim(); var obj2 = {  age: 20,  person: {   student: {    address: {     home: 'xxxxx'    }   }  } }; console.log(Mustache.render(tpl2, obj2));//-address: xxxxx,age: 20-</script>

In the above example, when rendering {# address} {/address}, the context object has become obj2.person. student. address references, so {home} is used for rendering obj2.person. student. address. home property, while {age} rendering, due to obj2.person. student. the address does not have the age attribute, so it will be searched in the upper context until the obj2 object is found, so it regards obj2.age as the rendering result.

There is also a way to do this without creating a new context through {# prop} or performing recursive rendering attributes:

<script id="tpl2" type="text/html"> -address: {{person.student.address.home}},age: {{age}}-</script><script> var tpl2 = document.getElementById('tpl2').innerHTML.trim(); var obj2 = {  age: 20,  person: {   student: {    address: {     home: 'xxxxx'    }   }  } }; console.log(Mustache.render(tpl2, obj2));//-address: xxxxx,age: 20-</script>

This method is actually quite understandable. As long as you know the current context object and then operate the person. student. address. home String Based on the attribute, you can find the desired value.

This article introduces a very useful front-end template engine, which contains the knowledge points that will certainly be used in daily work.

Articles you may be interested in:
  • Javascript lightweight template engine juicer User Guide
  • PHP's solution to conflicts with CSS/JSON in conventional template Engines
  • Laytpl exquisite and clever JavaScript template engine
  • High-performance JavaScript template engine implementation principles
  • Simple Introduction to simple js template engine
  • Introduction to common JavaScript template Engines
  • Node. js is suffixed with. html when the ejstemplate is used.
  • How to use javascript to write a simple page template engine

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.