Catalog
Recognizing Template Engine from a Practical Requirement
Ideas and Steps for Implementing a Template Engine
Recognizing Template Engine from a Practical Requirement
When we need to render a list of songs with js, because the data needs to be requested from the back end, the implementation can not write the data to death in html.
As shown below, we need to show such a list on the page.
But you can't write the data in the li tag as below.
At this time, there are two easy ways to solve this problem, one is html string splicing, the other is to build DOM objects.
First: HTML string splicing
Second: Building DOM objects
But both methods have great drawbacks:
The first method is easy to miss quotation marks and make splicing mistakes.
The second way is to increase the amount of code. Although jquery can be used to reduce the amount of code, it is still not the best choice.
The common feature of both methods is that they need to create a li tag and then dynamically capture the contents.
var li = '<li>'+ songs[i].name +'-'+songs[i].singer'</li>'
Here we can use a better way.
var li = stringFormat('<li>{0} - {1}</li>', songs[0].name, songs[0].singer)
Construct a stringFormat function and pass in parameters. The first parameter is the template, {0}, {1} will be replaced by two parameters passed in later, so that when the function is executed, it will return a string.
"<li>Some Like It Hot!! - SPYAIR</li>"
This stringFormat function is arguably the roughest template engine.
Input parameters:
'<li>{0} - {1}</li>'
It is a template, so-called template engine is able to parse the logic code containing special characters, simplify the string splicing front-end rendering plug-in.
But in this case, we must write this part of the function in the script tag, otherwise we can not distinguish which part is html code and which part is logic code, so we need special characters to express, this special character is delimiter.
For example, in this template, the delimiter used is <%>:
'<p>Hello, my name is <%name%>. I\'m <%age%> years old.</p>';
Ideas and steps for implementing a template engine:
The template for the example above is not complicated yet. When we encounter the following template, the situation will become different.
var template =
'My skills:' +
'<%if(this.showSkills) {%>' +
'<%for(var index in this.skills) {%>' +
'<a href="#"><%this.skills[index]%></a>' +
'<%}%>' +
'<%} else {%>' +
'<p>none</p>' +
'<%}%>';
var data = {
skills: ["js", "html", "css"],
showSkills: true
}
var TemplateEngine = function(template, data) {
return string
}
Now we need to clarify our thinking, we get a template, we need to let the code with delimiter package run like js code, and finally return to us a string containing the results of the run, what we need now is to implement it.
1. Create a new array and place the unbounded code part into the array
2. Recognize the js logical part, that is, the part wrapped by a delimiter, and take it out.
3. Imported data
So the last thing we get back is a string like this.
The final code is as follows:
var TemplateEngine = function(html, options) {
var re = /<%([^%>]+)?%>/g,
reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g,
code = 'var r=[];\n',
cursor = 0;
var add = function(line, js) {
js? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
(code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
return add;
}
while(match = re.exec(html)) {
add(html.slice(cursor, match.index))(match[1], true);
cursor = match.index + match[0].length;
}
add(html.substr(cursor, html.length - cursor));
code += 'return r.join("");';
return new Function(code.replace(/[\r\t\n]/g, '')).apply(options);
}
Maybe many people can't understand the final version. Now I will simplify the complex version and add comments to make it easier to understand:
var TemplateEngine = function(html, options) {
//Regularly matches the logical code part of the <%> package
var re = /<%([^%>]+)?%>/g;
//Regular matching contains keywords such as if|for|else|switch|case|break {|}
var reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g;
//Declare a string code to hold the final output
var code = 'var r=[];\n';
//Set a cursor to traverse the entire template string we passed in
var cursor = 0;
//Declare an add function to determine whether it is part of the js script or part of the string that needs to be added to the array
var add = function(line, js) {
if(js === true){
if(line.match(reExp)){
code = code + line + '\n'
}else{
code = code + 'r.push(' + line + ');\n'
}
}
else{
if(line !== ''){
code = code + 'r.push("' + line.replace(/"/g, '\\"') + '");\n'; //Quotation marks with escape characters
}else{
code = code + ''
}
}
return add
}
while( match = re.exec(html) ) {
var matchIdx = match.index;//Using re regular matching, the subscript of the next character of the last character of the first part matched in the template string
var matchPart = html.slice(cursor,matchIdx);//Cut the subscripts from cursor to matchIdx from the template string
add(matchPart);//Only the first parameter, line, is passed.
add(match[1], true); //If the second parameter is set to true, it goes directly into the judgement if(js===true).
cursor = match.index + match[0].length; //Cursor update
}
var rest = html.substr(cursor, html.length - cursor);//After matching, the last remaining part of the template string
add(rest);//This part also needs to be judged in the add function.
code = code + 'return r.join("");';//Finally, add the return statement
code = code.replace(/[\r\t\n]/g, '');//Remove tabs, carriage return and newline characters from the code string to make the code look more concise
return new Function(code).apply(options); //Run the code in the Function() function and bind the variable scope in the code to data.
}
Eventually we will get such a string code.
By using JS, we can provide "classes" of constructors.
You can run code
Be careful
The reason for this error is that the double quotation marks added in console.log do not add an escape character (), so the error will be reported.
End:
It took almost two days to finish this blog intermittently. It's not difficult to understand a thing, but how to use words to illustrate it is very nervous, but it's a small step forward.
Reference blog