一步一步实现一个Javascript模板引擎(三)

前两篇文章介绍了js模板引擎的基本原理,同时给出了核心代码,本文列出重构后的代码,当没提供数据的时候,返回一个渲染函数,具体如下:

/**
 * 模板引擎
 * @name    myTemplate
 * @param   {String}  模板字符串
 * @param   {Object}  数据
 * @return  {String, Function}  渲染好的HTML字符串或者渲染方法
 */
var myTemplate = function template() {
    'use strict';
    
    var args = Array.prototype.slice.call(arguments),
        tmpl = args.shift().replace(/\r|\n/g, "").replace(/"/g, '\\"'), //转义"号
        funcBody = 'var result = "";',
        func;

    funcBody += ' result += "' + tmpl + '";'; 
    funcBody = funcBody.replace(/<%=\s*([^>]*)\s*%>/g, function(match, $1) {
        return '" + ' + $1.replace(/\\"/g, '"') + ' + "'; //替换的同时,恢复<%=%>中被转义的"号
    });
    funcBody = funcBody.replace(/<%\s*([^>]*)\s*%>/g, function(match, $1) {
        return '";' + $1.replace(/\\"/g, '"') + 'result += "'; //替换的同时,恢复<%=%>中被转义的"号
    });

    funcBody += " return result;";

    func = new Function(funcBody);
    if (args.length > 0) {
        return func.apply(args.shift(), args); //返回渲染好的HTML字符串
    }
    
    return function() { //返回渲染方法
        args = Array.prototype.slice.call(arguments);
        return func.apply(args.shift(), args);
    }
};

myTemplate.version = '0.1.0';

该项目已经开源在Github上了,感兴趣的童鞋可以去查看源码及相关文档和demo。

项目名称:myTemplate
项目地址:https://github.com/guoyao/myTemplate

Posted in Web前端开发. Tags: , . 没有评论 »

一步一步实现一个Javascript模板引擎(二)

上一篇文章实现了一个简单的js模板引擎,但当时我们只是考虑了模板中的输出,没考虑模板中的js逻辑,下面我们来处理模板中的js逻辑问题。我们来处理一个复杂的模板,模板代码如下:

<script type="text/tmpl" id="template">
    <p><strong>Name:</strong> <%= this.name %></p>
    <p><strong>Age:</strong> <%= this.age %></p>
    <% if (this.gender) { %>
        <p><strong>Gender:</strong> <%= this.gender %></p>
    <% } %>
    <% if (this.children) { %>
        <p><strong>Children:</strong></p>
        <% for (var i = 0, len = this.children.length, child; i < len; i++) { 
            child = this.children[i]; 
        %>
            <ul style="background-color: #f5f5f5;">
                <li><strong>Name:</strong> <%= child.name %></li>
                <li><strong>Age:</strong> <%= child.age %></li>
                <% if (child.gender == "female") { %>
                    <li><strong>Gender:</strong> <%= child.gender %></li>
                <% } %>
            </ul>
        <% } %>
    <% } %>
</script>

以上模板中包含了较多的js逻辑代码,看起来很复杂,不好解析,其实不然,原理还是一样的,使用正则表达式替换,功能增强后的模板引擎代码如下:

var guiTemplate = (function () {
    function template(tmpl, data) {
        var funcBody = 'var result = "";',
            func;

        tmpl = tmpl.replace(/\r|\n/g, "").replace(/"/g, '\\"'); //转义"号
        funcBody += ' result += "' + tmpl + '";'; 
        funcBody = funcBody.replace(/<%=\s*([^>]*)\s*%>/g, function(match, $1) {
            return '" + ' + $1.replace(/\\"/g, '"') + ' + "'; //替换的同时,恢复<%=%>中被转义的"号
        });
        funcBody = funcBody.replace(/<%\s*([^>]*)\s*%>/g, function(match, $1) {
            return '";' + $1.replace(/\\"/g, '"') + 'result += "'; //替换的同时,恢复<%=%>中被转义的"号
        });

        funcBody += " return result;";

        func = new Function(funcBody);
        return func.call(data);
    }
    return {
      template: template
    };
})();

调用代码如下:

var template = document.getElementById("template").innerHTML,
    html = guiTemplate.template(template, {
        name: 'guoyao',
        age: 26,
        gender: 'male',
        children: [
            {
                name: 'child 1',
                age: 5,
                gender: 'female'
            },
            {
                name: 'child 2',
                age: 3,
                gender: 'male'
            }
        ]
    });

生成的html如下:

<p><strong>Name:</strong> guoyao</p>        
<p><strong>Age:</strong> 26</p>                    
<p><strong>Gender:</strong> male</p>                            
<p><strong>Children:</strong></p>                            
<ul style="background-color: #f5f5f5;">                    
    <li><strong>Name:</strong> child 1</li>                    
    <li><strong>Age:</strong> 5</li>                                            
    <li><strong>Gender:</strong> female</li>                                    
</ul>                            
<ul style="background-color: #f5f5f5;">                    
    <li><strong>Name:</strong> child 2</li>                    
    <li><strong>Age:</strong> 3</li>                                    
</ul>

本文我们基本上实现了一个比较完整的js模板引擎,当然跟目前流行的开源模板引擎比较起来,我们的还不够完善,有空的时候我会继续完善它,不久将开源在Gitbub上,有兴趣的可以关注一下。

Posted in Web前端开发. Tags: , . 没有评论 »

一步一步实现一个Javascript模板引擎(一)

目前Web前端越来越复杂,Javascript MVC / MVVM思想也开始流行起来。Javascript模板引擎作为数据与界面分离工作中最重要一环,越来越受开发者关注。那么什么是模板引擎?简单点说,模板引擎的功能就是将一个字符串中的待定变量用js对象的对应属性来替换。目前流行的js模板引擎有:Mustache、Underscore、doT、Handlebars、Juicer等。其实要自己实现一个模板引擎并不太困难,其原理都大同小异。接下来就跟着我一步一步来实现一个js模板引擎。

示例模板字符串如下:

<p>Name: <%= this.name %></p>
<p>Age: <%= this.age %></p>

模板引擎处理后的字符串如下:

<p>Name: Guoyao</p>
<p>Age: 27</p>

模板引擎代码如下:

var guiTemplate = (function () {
    function template(tmpl, data) {
        var funcBody = 'var result = "";',
            func;

        tmpl = tmpl.replace(/\r|\n/g, "").replace(/"/g, '\\"'); //转义"号
        funcBody += ' result += "' + tmpl + '";'; 
        funcBody = funcBody.replace(/<%=\s*([^>]*)\s*%>/g, function(match, $1) {
            return '" + ' + $1.replace(/\\"/g, '"') + ' + "'; //替换的同时,恢复<%=%>中被转义的"号
        });

        funcBody += " return result;";

        func = new Function(funcBody);
        return func.call(data);
    }
    return {
      template: template
    };
})();

调用代码如下:

var tmpl = '<p>Name: <%= this.name %></p><p>Age: <%= this.age %></p>';
guiTemplate.template(tmpl, {name: 'Guoyao', age: 27});

至此,我们只是考虑了模板中的输出,没考虑模板中的js逻辑,下一步我们来处理模板中的js逻辑问题。

Posted in Web前端开发. Tags: , . 没有评论 »

Flex + Rails构建Web Application

前一段时间一直忙于做毕业设计,花了半个月左右时间终于完成。我的毕业设计题目是:基于B/S模式的WEB选课系统的设计与实现,因为喜欢Flex开发,再加上Flex完美的用户体验,前端开发技术就毫不犹豫选择了Flex;服务器端技术本打算用Java,因为用Java的话,就可以用LiveCycle Data Services来与Flex高效通信了,但由于我的本本太过陈旧,跑一个独立安装的Flex Builder已经够呛,根本无法同时跑MyEclipse。这时我才深刻领悟“工欲善其事必先利其器“的道理!可是没钱买新本本,就只好想其它的方法!因为以前学过一段时间的Rails,于是就想服务器端可不可以用Rails来做,但因为以前从来没有用Flex+Rails这个组合来开发Web Application,不知道他们之间怎样进行通信,当然用HttpService是可以通信的,但效率不高,用起来也不是很方便,就考虑Rails有没有类似LiveCycle Data Services插件,果然功夫不负有心人,让我找到了Rails的一个插件:RestfulX,下面是官方的简介:

RestfulX is a framework that brings the design principles and productivity ofRails to Adobe Flex and AIRdevelopment and makes integration with RESTful Web Services as simple as possible. If you want to use Ruby on Rails, Merb, Sinatra, CouchDB or Google App Engine and you want a UI that puts the word Rich into Rich Internet Applications give RestfulX a spin. It only takes 5 minutes to get started. Instead of WSDL, SOAP or other complex specifications you’ll find a few common conventions that help you to abstract your application from repetitive CRUD code and switch/synchronize between various data providers with minimal effort.

至于如何使用,大家可访问Restfulx的网站:http://restfulx.github.com/

该插件可以自动生成一些东西,其实也就是生成了一个基于Flex + Rails的、可对数据库进行CRUD操作的Web Application。这个自动生成的例子很好,是学习使用它的最好方法,我就是靠看这个例子的源码来学习使用的,但这个例子只用到了一些最基本的API,如果想深入学习的话,建议去看官方的开发文档。

项目中我还用到了Flex的一个MVC框架,相信Flex开发者们都应该很熟悉了,就是:Cairngorm。这个我就不介绍了。

Posted in Flex. Tags: , , . 没有评论 »