Detailed JavaScript template engine Mustache.js_javascript tips

Source: Internet
Author: User
Tags cas object object script tag

This article summarizes its use methods and some of the use of experience, the content is not very advanced, is purely introductory content, see can. But if you have not used this kind of JavaScript engine library, then this article is still worth reading, I believe that after you understand its powerful features and simple usage, you will be eager to use it for your work.

1. From a simple real need to talk about
at present, the company has done a unified development platform, the backstage encapsulation of the MVC interface and data additions and deletions to check the interface, the front-end I used bootstrap+ handwritten various components of the way to get a set of development framework; The CAS is integrated with CAS, first a set of unified rights management system, The system is the first subsystem of our development platform to manage the menu and authorization of all subsystems and to manage the organization and users of the entire company, and then we continue to develop business system A and business system B. Since these three subsystems correspond to three Java projects, and when deployed, three applications were deployed in Tomcat, there is now a requirement:

    • 1 after each system login, click on the system name, you can expand a drop-down menu, display all the permissions of the subsystem;
    • 2 and then the user clicks on other subsystems, you can switch to the selected system, to other systems, since all do this pull-down menu, so you can also switch back from the system;
    • 3 If the user has only one system permission, the Drop-down menu is not displayed.

The demand is actually quite simple, the prototype is probably this way:

The function realization method is, after each subsystem login completes, calls obtains the system list the interface, uses the JS to render a drop-down menu to come out, this interface returns the format:

Data: [
 {
  "SortOrder": 1,
  "iscurrent": True, 
"Systemhttpurl": "Http://xxxx:8080/permission",
  "" SystemName ":" Unified Rights 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 don't use the template engine, the traditional way to parse the data and turn it into an HTML string is usually:

function data2html (data) {data = Data | |
 []; var html = [' <ul class= ' nav navbar-nav navbar-left nav-system ' > ', ' <li class= ' dropdown ' > ', ' <a hr

 ef= "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 fa-caret-down" ></i></a><ul class= "
 Dropdown-menu ">");
 Data.sort (function (A, b) {return a.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>&
 Lt;/li> ');
 } html.push (' </ul></li></ul> '); ReturnHtml.join (");

 }

There are many drawbacks to this type of string concatenation:

    • 1 trouble, especially the concatenation logic is complex, the concatenation string is very long;
    • 2) difficult to maintain, a slight careless will be mistaken for the corresponding relationship between the labels;
    • 3) structure is not clear.

The tool to simplify this scenario is the template engine, the template engine's technology is the first, if you use JSP, you must know that JSP is a template, used to parse the rendering of data, other background template engine and velocity and freemarker and so on. The front end of the template engine also has a lot, mustache.js is a more popular one, git on more than 8,000 praise, if this problem we use mustache.js to do, can become this:

Define template var _template = [' <ul class= ' nav navbar-nav navbar-left nav-system ' > ', ' <li class= ' d by some tags corresponding to the attribute name Ropdown ">", ' <a href= ' javascript:; "class=" Dropdown-toggle "data-toggle=" dropdown "title=" Switching System ">", ' {{curs Ystemname} {{#multiple}}<i class= ' fa Fa-caret-down ' ></i>{{/multiple}} ', ' </a> ', ' {{#multiple}}&l T;ul class= "Dropdown-menu", ' {{#systems}}} ', ' {{^first}}<li role= ' separator ' class= ' divider ' ></li&gt ;   {{/first}} ', ' <li> ', ' <a href= ' {{Systemhttpurl}}} ' target= ' _self ' >{{systemName}}</a> ', '

</li> ', ' {{/systems}} ', ' </ul>{{/multiple} ', ' </li> ', ' </ul> '].join (');
Initialize this template mustache.parse (_template); function data2html (data) {data = Data | |
 [];
 var cursysary = Data.filter (function (s) {return s.iscurrent;});
 Data.sort (function (A, b) {return a.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: ", mult Iple:!!
Data.length, systems:data});

 }

Comparing two code, you will find that the following code, compared to the previous one, has these advantages:

    • 1 The structure is clear, all the HTML to be rendered is defined in one position, and there is no splicing phenomenon;
    • 2 The logic is clear, those in the template tag, actually with the template rendering newsletters in the object's attribute names are corresponding;
    • 3) Easy to maintain, and to delete labels are only used to adjust the corresponding array of templates on the line.

With this example, it should be possible to have a general idea of the template engine, which is becoming more common in front-end development, especially in the application of front and back end separation, and is already the content of the infrastructure of such applications. Mustache.js is a very easy to use engine implementation, the next content will be the common template configuration for this tool to introduce and cooperate with practical examples to illustrate, hope that you like this tool:

2. Use of mustache
Mustache's use is very simple, first through the script tag to introduce its JS file, and then follow the following steps:
1 Define template strings
There are 2 ways to define a template, which is seen in the previous section, directly using [...]. Join (") is defined in the JS code, and mode two directly defines the template content in HTML with script:

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

Then, before compiling the template, define the original template string by obtaining the innerHTML of the TPL:

var TPL = document.getElementById (' TPL '). Innerhtml.trim ();

Specific ways to define the template, you can refer to the following recommendations:
If the template is to be used for multiple pages, it is recommended that the template be defined in the JS code; If the template is for the current page only, the recommendation is directly defined into the script tag, which is easier to manage.
2 Pre-compiling template
Assuming that the original template string is already defined and referenced with a TPL variable, you can precompile the template by using the following code:

Mustache.parse (TPL);

Note that the precompiled TPL is no longer the original template string, and even the data type becomes an array type, which is the result of precompilation.
3) render template
The rendering method is simple:

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

Obj refers to a data source object that mustache the label of those attributes in the template and replaces it with the object's contents according to the agreed rules. Htmlafterrendered is the replacement string, which you can use to complete the DOM operation you need.

3. The idea of mustache
The core of mustache is the label and Logic-less. From the previous code, you can see that when you define a template, you use a tag such as {{name}}, and {{#systems}}{{/systems}}, which is the label for mustache, except that it replaces <> with {{}}, so that the HTML tag <> confusion. Logic-less, can be translated as light logic, because the template will not be used to define the If-else, there will be no circular encoding, all with the label to solve, its label is very simple, but can cope with all the scenes, after reading this article, you will be surprised to find that, With just a few tags, you can almost solve all the problems:
{{prop}}}
{{{prop}}}}
{{#prop}}} {{/prop}}}
{{^prop}}} {{/prop}}}

4. {{prop}} label
This label is the most used in the mustache template, you can convert the value of the prop attribute on the data source object to the string for output, the following is the same property, corresponding to different types of values, A test that outputs results after mustache rendering (the short horizontal line before and after it is designed to make the rendering of this tag look clearer):

<script id= "Tpl1" type= "text/html" >-{{prop}}-</script> <script> var tpl1 = document.getElementById (
 ' Tpl1 '). Innerhtml.trim ();
 Mustache.parse (TPL1);
 Test Falsy value Console.log (Mustache.render (TPL1, {prop: '});//--Console.log (Mustache.render (TPL1, {prop: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 Simple Object Console.log (Mustache.render (TPL1, {prop: {name: ' Jason '}});//-[object object]-//test 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 out of a 2016 15:38:46 (China Standard Time)-///Test Simple Object var for custom ToString
 Obj1 = {name: ' Jason '};
 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 (must Ache.render (TPL1, {prop:1.2}));//-1.2-console.log (Mustache.render (TPL1, {prop: ' yes '});//-yes-//Test function Consol  E.log (Mustache.render (TPL1, {prop:function () {}});//--Console.log (Mustache.render (TPL1, {prop:function ()) {return ' it\ ' 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 for the mustache render {{prop}}} label is:

    • 1 if the value referenced by prop is null or undefined, render to an empty string;
    • 2 if prop is referring to a function, this function is automatically executed during rendering, and the return value of this function is rendered as a render result, if the return value is null or undefined, the render result is still empty, otherwise the return value is converted to a string as the rendering result (note that the last use case , the function code is rendered out directly);
    • 3 other scenes, direct the value of the prop reference to the string as the rendering result.

Because by default, when mustache renders prop, it is either URL-coded or HTML-encoded for the original value of prop, so there is a use case rendering that turns the single quotation mark in English into an HTML entity character:

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

If you want to block this encoding behavior, simply change the label form to {{prop}}}:

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

5. {{{#prop}}{{/prop}} label
This is very powerful for tags, and can complete both if-else and For-each as well as dynamically rendered template functionality. Between this pair of tags, you can define other template contents and nest all tags. Next look at how mustache uses this pair of tabs to complete these three template features.

1) If-else Rendering

The contents of a label are rendered only if the Prop property exists on the data source object and is not a Falsy value (JavaScript 6 falsy value: Null,undefined,nan,0,false, empty string) and is not an empty array. Otherwise they will not be rendered:

<script id= "tpl2" type= "text/html" >-{{#prop}}content{{/prop}}-</script> <script> var tpl2 = documen
 T.getelementbyid (' tpl2 '). Innerhtml.trim ();
 Mustache.parse (TPL2);
 Test 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 empty array Console.log (Mustache.render (TPL2, {prop: []});//--//Test nonexistent attribute Console.log (Mustache.render (TPL2, {prop2:true}));//- -//Test function Console.log (Mustache.render (TPL2, {prop:function () {}});//--Console.log (Mustache.render
  , {prop:function () {return false;
  });//--Console.log (Mustache.render (TPL2, {prop:function () {return []); }));//--//Test Simple Object Console.log (Mustache.render (TPL2, {prop: {name: ' Jason '}});-content-//Test Date Object Console.log (Mustache.render (tpl2, {prop:new date ()}))//-content-//test Boolean number string consol
 E.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 Returns a function Falsy of a non-console.log, non-empty Array (
 Mustache.render (TPL2, {prop:function () {return ' it\ ' A fun '}});//-content-</script>

The special point in the above use case is when the prop attribute refers to a function, and {{#prop}} automatically invokes the function and takes the return value of the function as the basis for if-else rendering logic, that is, if the function returns a Falsy value or an empty array, So the content between the tags is still not displayed.

2) For-each Rendering

When the Prop property refers to a non-empty array, the the contents of this pair of tags are iterated according to the size of the array, and when an array element is an object, the object is also used as the context for each iteration so that the label of the iteration can refer directly to the attributes 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>

As you can see from this test result, the template content between {{#prop}}{{/prop}} is iterated two times according to the array referenced by prop, and the value of the Name property on the array element object is output directly inside the label of the {{name}}.

If the Prop property refers to a function, but the return value of the function is an array type, then the For-each render is still 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 refers to a function, and the return value of the function is a function, mustache calls the returned function again and passes it 2 arguments: text represents the original template content, render represents the object that performs rendering within mustache, So that within this function, you can use the Render object, combine the original template content, customize the rendering logic, and use the return value of the function as the render result (this return value renders the logic exactly the same as the {{prop}} label):

<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}} label
This pair of tags, which performs the opposite logic with the if-else rendering of {{#prop}}{{/prop}}, is not displayed until the Prop property does not exist, or if it refers to a falsy value, or an empty array, the contents of the label will not appear:

<script id= "tpl2" type= "text/html" >-{{^prop}}content{{/prop}}-</script> <script> var tpl2 = documen
 T.getelementbyid (' tpl2 '). Innerhtml.trim ();
 Mustache.parse (TPL2); Test 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 empty array Console.log (Mustache.render (TPL2, {prop: []});//-content-//Test nonexistent attribute Console.log (mustache.render (TPL2, {prop2:true})); /-content-//Test function Console.log (Mustache.render (TPL2, {prop:function () {}});//-content-console.log (must
  Ache.render (TPL2, {prop:function () {return false;
  });//-content-console.log (Mustache.render (TPL2, {prop:function () {return []); }));//-contenT//Test Simple Object Console.log (Mustache.render (TPL2, {prop: {name: ' Jason '}});//--//Test Date object Console.log (TP 

 L2, {prop:new Date ()});//--//Test Non-empty array Console.log (Mustache.render (TPL2, {prop: [{name: ' Jason '},{name: ' Tom '}]});//-- Test Boolean number String Console.log (Mustache.render (TPL2, {prop:true}));//--Console.log (Mustache.render, {PR op:1.2}));//--Console.log (Mustache.render (TPL2, {prop: ' yes '});//--//Test Returns a function Falsy of a non-console.log, non-empty Array (Mustac He.render (TPL2, {prop:function () {return ' it\ ' s a fun '}});//--//Test the function Console.log (musta Che.render (TPL2, {prop:function () {return function (Text,render) {return ' <b> ' + render (text) + ' &LT;/B&G
   t; '

 }});//--</script>

7. Render Context
Mustache has a concept of a rendering context stack that, at the beginning of the template rendering, takes the data source object as the current rendering context and presses the context stack. When the {{#prop}} tab is encountered, if prop refers to an object or an array of Non-empty objects, or if prop refers to a function, and the function returns an object or an array of Non-empty objects, it takes the object or the element of the array as the current rendering context and presses into the context stack, and when the tag is rendered, the context is ejected and the context used for the previous layer of the label is restored. Because the {{#prop}} tags can be nested multiple layers, there is a multi-tier context in which the template renders. Mustache, when parsing a label, finds the current context object based on the label name and finds it in the upper-context object if it does not exist, and is rendered with the value of that layer context object as long as it is found at one level.

<script id= "tpl2" type= "text/html" >-{{
 #person}}{{#student}}{{#address}}address: {{home}},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 example above, when the {{#address}}{{/address}} is rendered, the context object has become the object referenced by Obj2.person.student.address, so {{home}}} The Obj2.person.student.address.home attribute is used for rendering, and when {{age}} is rendered, Because the obj2.person.student.address does not exist The age attribute, it will be found in the upper context, until the Obj2 object is discovered, so that Obj2.age is treated as a rendering result.

There is also a way to create a new context without using {{#prop}}, or to render properties of a recursive rendering property:

<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 '
    }
 }}};< C15/>console.log (Mustache.render (TPL2, Obj2));//-address:xxxxx,age:20-
</script>

This approach is very well understood, as long as you know the current context object, and then based on the properties of the string person.student.address.home, of course, you can find the desired value.

This article introduces a very useful front-end template engine, covering the content of the daily work will certainly be used in the knowledge points, I hope you like.

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.