There are many, many js template engines. I used to often use art-template, and sometimes vue was used as a template engine.
Until...
At the beginning of the year, I was still in the previous project team. At that time, the code specification wasYou cannot use [external code] without permission,Oops.
If there is a need, then write it, but later it is not used for some reasons. Later, we divided the production line and built a set of builds by myself. After using it for a few months, I felt very comfortable. I rewrote this small piece of code according to more popular standards and shared it with everyone.
https://github.com/shalldie/mini-tpl
The first is to choose template syntax, ejs syntax is the first choice, because it is popular, there is no need to learn it Things like directive template engines.
If you have written jsp or asp/asp.net, you can get started directly.
<body> <p id="root"></p> <script id="tplContent" type="text/html"> <ul> <% for(var i=0; i<data.length; i++){ var item = data[i]; if(item.age < 30){%> <li>我的名字是<%=item.name%>,我的年龄是<%=item.age%></li> <%}else{%> <li>my name is <%=item.name%>,my age is a sercet.</li> <%}%> <% } %> </ul> </script> <script src="../build/mini-tpl.min.js"></script> <script> var data = [{ name: 'tom', age: 12 }, { name: 'lily', age: 24 }, { name: 'lucy', age: 55 }]; var content = document.getElementById('tplContent').innerHTML; var result = miniTpl(content, data); document.getElementById('root').innerHTML = result; </script> </body>
If you want to use it this way, then let’s analyze how to achieve it.
1 const content = 'console.log("hello world");'; 2 3 let func = new Function(content); 4 5 func(); // hello world
new Function ([arg1[, arg2[, ...argN]],] functionBody)
functionBody A string <strong></strong> containing a
JavaScript statement that includes the function definition.
Functions generated using the Function constructor do not create closures in the context in which they are created; they are generally created in the global scope.
When these functions are run, they can only access their own local variables and global variables, and cannot access the scope of the context generated by the Function constructor being called. (MDN)
That is to say:
You can use new Function to dynamically create a function to execute a dynamically generated function definition js statement.
The function generated through new Function has a global scope.
There are three ways to pass parameters: Put the variable globally (nonsense)
, Function parameter passing
,Use call/ apply passes the value to this
of the function.
At first I used call to pass the value, but now that I thought about it it was not very elegant, so I changed it to passing it by parameters. That's it:
const content = 'console.log(data);'; let func = new Function('data', content); func('hello world'); // hello world
So far, the prototype is here. Let’s break it down below.
Look at the template first:
<% for(var i=0; i<data.length; i++){ var item = data[i]; if(item.age < 30){%> <li>我的名字是<%=item.name%>,我的年龄是<%=item.age%></li> <%}else{%> <li>my name is <%=item.name%>,my age is a sercet.</li> <%}%> <% } %>
js logical part, wrapped by <%%>
, The placeholder for the js variable is wrapped by <%= %>
, and the rest is the ordinary html string part to be spliced.
In other words, there are three types of parts that need to be found using regular expressions:
<%%>
The js content of the logical part
##<%=%> The js content of the placeholder part
plain text Content
js part and
splicing part.
of int type, there is a function splice attribute of type. Then the browser will think it is an array.
If other properties inside are sorted by index, they can even be displayed on the console like items in an array. This method of judgment is calledduck typing. If something looks like a duck and quacks like a duck, then it is a duck 0_o
Back to text , this requires extracting the js logical part and text from the template multiple times. For each extraction, the extracted content must be obtained. This time, the last index item is matched (used to lift the text content). So I chose RegExp.prototype.exec . For example, RegExp.prototype.exec returns a collection (pseudo array), and its type is like this:Description | |
---|---|
Match All strings | |
Group capture in brackets | |
The matched character is at the 0-based index of the original string | |
Original string | ## |