Knockoutjs Learning Note 01: From stitching strings to writing template engines

Source: Internet
Author: User

Opening

As for knockout's article, there have been many great gods written in the garden, and they are well written. In fact, knockout learning is still very easy, look at the official website of the demo and garden articles, practice can be used to practice (only use, not including research source). The reason why want to write this series, mainly want to record their learning and application process, but also hope to give beginners a little help.

Since the learning process is one step at a pace, from the initial solution, to the optimization process, to the final implementation of the program. With the thought and the contrast, it will be more understanding of the benefits of this thing, why use it, what circumstances to use it. OK, the website study link is?:Knockoutjs

Preparation examples  

The process is this: The foreground sends an AJAX request, returns a JSON string in the background, generates HTML from the foreground, and inserts into the DOM. We are familiar with this process, and then we will do this in a variety of ways.

Use jquery to write a simple way to send a request, as follows:

Window. Tester = {    callback:function (fn) {        $.ajax ({            URL: "). /handlers/getcourse.ashx ",            success:function (data) {                data = $.parsejson (data);                fn (data);}}        );}    }

The corresponding entity object in the background, as follows:

    public class Courseinfo    {public        string CourseID {get; set;}        public string IconPath {get; set;}        public string Coursename {get; set;}        public string TeacherName {get; set;}        public string CreatedDate {get; set;}        public int Studynumber {get; set;}    }

The HTML is as follows:

        <ul id= "Course" >            <li>                <a href= "/default.aspx?courseid=001" >                    <div class= " Course-img ">                                            </div>                    <div class=" Course-info ">                        <div class=" names ">                            < Span>jquery Source parsing </span>                            <span class= "fr" > Miss Li </span>                        </div>                        <div class = "Pros" >                            <span>2015-08-08</span>                            <span class= "FR" >100 people learning </span>                        </ div>                    </div>                </a>            </li>        </ul>

Interface effect:

First, stitching strings

I believe many people began to use splicing strings to generate DOM elements, and then the more write more, more and more chaotic ..., write to oneself all do not understand very much, finally simply waved to others to see. None of us want to do this, and a friend with code cleanliness should be crazy to see this.

Let's look at the implementation of the above effect, with the concatenation of the string is how, the code is as follows:

 Tester.callback (function (data) {for (var i = 0; i < data.length; i++) {var courseimg = "<div class= ' course-img ' ></div>"; var names = "<div class= ' names ' ><span>" + data[i]. Coursename + "</span><span class= ' fr ' >" + data[i].            TeacherName + "</span></div>"; var pros = "<div class= ' pros ' ><span>" + data[i]. CreatedDate + "</span><span class= ' fr ' >" + data[i].            Studynumber + "people learning </span></div>"; var item = "<li><a target= ' _blank ' href= ' default.aspx?courseid=" + data[i].            CourseID + ">" + courseimg + "<div class= ' Course-info ' >" + names + Pros + "</div></a></li>";        $ ("#course"). Append (item); }    });

You can quickly draw the following points:1. Stitching it up is a hassle. 2. Cannot give a clear DOM structure 3. It's cumbersome to modify strings everywhere. in the actual project, we should try to avoid this situation.

Second, clone Dom

In order to solve the above shortcomings, we can put the HTML template first, and hide. When needed, clone one copy to generate HTML. The code is as follows:

 <div id= "tmp" class= "Noen" > <ul> <li id= "Tmpitem                    "> <a> <div class=" course-img ">  </div> <div class= "Course-info" > <div class= "Names"                        > <span></span> <span class= "FR" ></span> </div> <div class= "Pros" > <span>                    ;</span> <span class= "FR" ></span> </div> </div> </a> </li> </ul> </div> 
 Tester.callback (function (data) {for (var i = 0; i < data.length;            i++) {var item = $ ("#tmpItem"). Clone (); Item.find ("a"). attr ("href", "default.aspx?"). Courseid= "+ data[i].            CourseID); Item.find (". Course-img>img"). attr ({"src": data[i]. IconPath, "alt": Data[i].            Coursename}); Item.find (". Names>span:eq (0)"). Text (Data[i].            Coursename); Item.find (". Names>span:eq (1)"). Text (Data[i].            TeacherName); Item.find (". Pros>span:eq (0)"). Text (Data[i].            CreatedDate); Item.find (". Pros>span:eq (1)"). Text (Data[i].            Studynumber + "People learning");        $ ("#course"). Append (item); }    });

Looks a lot better than stitching strings. Here we refer to the concept of " template ", but it is not really a template, so-called template should be: The basic content is ready, the poor data, as long as the data passed over, you can generate complete content . As you can see, we're going to parse the data ourselves, and then build the content, not the automated process. It's best if you can generate HTML like this: var html = template ("#tmpID", data); Tmpid indicates that the template's id,data is data, which generates HTML without having to go for the for traversal. Yes, this is how most of the template engines are implemented.

Third, template engine

About JS template engine There are many, I will also be introduced in the next article alone. But here I do not want to immediately use off-the-shelf, our own implementation of the first try!

3.1 Basic version

First we need to find the location of the real data in the string, which is usually done by "placeholder", for example: ${$}, and then replace the placeholder with the actual data. Find placeholders can be implemented with regular expressions, and replace placeholders with string manipulation.

  For example, the string: My name is ${name$}, I am ${year$} years old. The data is: {name: "Tom", year:18}. we want to generate the final result: My name is Tomand I am years old.

First write a regular expression that matches the placeholder:/\${(?:. (?! \$}))*.)? \$}/g (Note: regular level, card for a long time ...), a good friend in reply write better! )。 The implementation code is as follows:

    var reg =/\${(?:. (?! \$}))*.)? \$}/g;     var str = "My name is ${name$}, I am ${year$} years";    var data = {        name: "Tom",        year:18    }    var match;    while (match = reg.exec (str)) {        str = str.replace (match[0], data[match[1]]);    }    

A simple explanation: The core is the Exec method, which returns an array of values that match to the string, its location, and so on. Match[0] is a placeholder; match[1] is the content within the placeholder (such as name). This allows all matches to be found through a loop.

3.2 Improved version

The above example is simply too simple to look at a slightly more complex structure. the strings are: My name is ${name$}, and I am ${info.age$} years old. The data is: {name: "Tom", info: {age:18}}. according to the above, the correct result cannot be obtained, because the match match[1] is "info.age", and data["Info.age"] obviously cannot get to 18. If you can write JS in a string, for example: THIS.name or This.info.age, the runtime this is passed and executed by us, so the problem is solved.  Here are two questions:1. How do I write JS code in a string? How does 2.this dynamically decide?

To write code execution in a string, the Function can be implemented. function receives the arguments of the string type, preceded by the arguments of the functions, and the last is the execution body of the function. For example: var fn = new Function ("Arg1", "arg2", "return arg1 + arg2;"); FN is a function that receives two parameters. Can be performed to obtain results: Console.log (FN); 3. So how is this determined by our dynamic? The answer is: the object is impersonating. JS call, apply is used to achieve the object impersonation.

Solve these two problems, the implementation is much easier, as follows:

    var code = "Return ' My name is ' + THIS.name + ', I am ' + this.info.age + ' years old ';";    var fn = new Function (code). Apply (data);    Console.log (FN);

Here we create a function, which is the code,this point to the data object. Note that THIS.name cannot be added here, otherwise it will be stitched as a normal string. String concatenation is too troublesome, to see a good practice on the Internet, through the implementation of the array, the code is as follows:

    var code = "var result = [];"    Code + = "Result.push (' My name is ');";    Code + = "Result.push (this.name);";    Code + = "Result.push (' I am ');";    Code + = "Result.push (this.info.age);";    Code + = "Result.push (' years old ');";        Code + = "Return Result.join (');";         var fn = new Function (code). Apply (data);    Console.log (FN ());

Similarly, the data section cannot be added '. This way is ingenious, when FN executes, it will be from var result = []; Start execution, this is the data object, and the last generation string is returned. Here we simply encapsulate:

    var str = "My name is ${this.name$}, I am ${this.info.age$} years";    var data = {        name: "Tom",        info: {age:18}    }    function template (HTML, data) {        if (!html) {            return;< c8/>}        var reg =/\${(?:. (?! \$}))*.)? \$}/g;        var cursor = 0;        var code = "var result = [];\n";        var match;        while (match = reg.exec (html)) {            code + = "Result.push ('" + html.substring (cursor, match.index) + "'); \ n";            Code + = "Result.push (" + match[1] + "); \ n";            cursor = Match.Index + match[0].length;        }        Code + = "Result.push ('" + html.substring (cursor) + "'); \ n";        Code + = "Return Result.join (')";                Console.log (code);        return new Function (Code.replace (/\n/g, "")). Apply (data);    }    Console.log (Template (str, data));  

3.3 Final version

Many times back in the background are JSON array strings that need to be handled using logical judgments and loops. There is a need for a regular:/(^ ()? ( if|for|else|switch|case|break| {|})) (. *)?/g is used to match the keyword of the judgment loop. It is important to note that when these keywords are encountered, they cannot be push into the array, but should be executed as part of the program, for example:

var result = [];

for (Var i=0;i<10;i++) {

Result.push (this.name);

}

...

In combination with the above, encapsulate a final version, as follows:

    function template (ID, data) {if (!id) {throw new Error ("template ID cannot be empty!        ");        } var Jtmpl = $ (ID);        if (jtmpl.length <= 0) {throw new Error ("Cannot find the template ID:" +id+ ");        } var html = jtmpl.html ();        if (!html) {return HTML;        } HTML = html.replace (/\ "/g," \\\ ""); var reg =/\${(?:. (?! \$}))*.)?                      \$}/g; var Logicreg =/(^ ()? ( if|for|else|switch|case|break| {|}))        (. *)?/g;        var cursor = 0;                var code = "var result = [];\n";        var match;                var key;                        while (match = reg.exec (html)) {code + = "Result.push ('" + html.substring (cursor, match.index) + "'); \ n"; Code + = Match[1].match (Logicreg)?                        MATCH[1]: "Result.push (" + match[1] + ");";            Code + = "\ n";        cursor = Match.Index + match[0].length;        } code + = "Result.push ('" + html.substring (cursor) + "'); \ n"; Code + = "RetuRN Result.join (")";        Console.log (Code.replace (/\n/g, ""));    return new Function (Code.replace (/\n/g, "")). Apply (data); }

  We're trying to use this template to do the same thing with the same string as the clone Dom. Define the template first:

<script type= "Text/tmpl" id= "Coursetmpl" > ${for (var i=0,length=this.length;i<length;i++) {$} <li> <a href= "Default.aspx?courseid=${this[i]. courseid$} "> <div class=" course-img ">  </div> <div class=" Course-info "> <div C lass= "Names" > <span>${this[i]. teachername$}</span> <span class= "fr" >${this[i].                        coursename$}</span> </div> <div class= "Pros" > <span>${this[i]. createddate$}</span> <span class= "fr" >${this[i]. studynumber$} people learning </span> </div> </div> </a> &lt ;/li> ${}$}</script>

Once the template is defined, there is only one line of execution code! As follows:

    Tester.callback (function (data) {        $ ("#course"). HTML (Template ("#courseTmpl", data);    });

By using the template engine, I just need to define the template, pass the data, and the rendering work is done automatically by the template engine.

Here is a little bit of knowledge, the script's Type property is set to: Text/tmpl, this property is not known to the browser. If the type of script is supported by the browser (such as Text/javascript), it will be executed as a script or a download script is requested via the SRC attribute, which is ignored if it is not supported by the browser. So it can be used to store data, and most templates are also defined in this place.

Iv. Summary

The template engine above is very simple, only 30 rows or so, but it can actually solve some simple problems. In fact, it has many problems not to be considered, it is more complicated to write, it is not suitable for the changeable demand, so it is recommended for simple application or learning. Well, it lets us understand the whole idea and the process of running the template.

There are actually a lot of ready-made template engines, and one of them will be introduced in the next article.

Thanks for reading.

Knockoutjs Learning Note 01: From stitching strings to writing template engines

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.