Web.js MVC between client and server

转载于:http://cnodejs.org/topic/4f16442ccae1f4aa270010c3

 

 

Web.js 是一个 为简化 HTTP 开发而设计的 Web Framework,它致力于以最简单的语法进行开发高性能的应用。

Web.js between client and server 是指 web.js 这个文件可以同时在客户端和服务端使用吗?

不是的。。这个先不管。。先来看看其他“无关”的。。

以下是 Wikipedia 对 MVC 的解释:

MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。






先来说说前端 MVC


现在国内来说,相对优秀的前端 MVC 架构是来自豆瓣说的 [(Backbone.js + Underscore.js) + Mustache.js + jQuery]

M - Model


Backbone.js 和 Underscore.js 是暂时来说国内公认的最好的一组 Model 框架

  1. 高性能
  2. 强自定义度
  3. 高灵活性
  4. …………

Backbone.js

//Model of Backbone

var Person = Backbone.Model.extent({

    sayHello: function () {

        alert('Hey, I`m ' + this.get('name') + '.');

        return this;

    },

    setName: function (name) {

        this.set({'name': name});

        alert('My name is ' + this.get('name') + '.');

        return this;

    }

});



var Will = new Person;



Will.setName('Will Wen Gunn')    // --> My name is Will Wen Gunn.

    .sayHello();                // --> Hey, I`m Will Wen Gunn.

其中 Backbone.Model 可以理解为经过封装的 Class 类型,然后 Person 是一个经过 extend 拓展的自定义 Class 类型,

Will 则是继承了 Person 的一个 Model 对象。
//Model of Underscore

$.getJSON(location.origin + '/persons')

    .done(function (data) {

        sessionStorage.persons = data;

        var persons = JSON.parse(sessionStorage.persons);

        // --> [{name: 'Will Wen Gunn'}, {name: 'Foo'}, {name: 'Bar'}]

        $('body').append(

            JSON.stringify(

                _.map(persons, function (person) {

                    if (person.name == 'Will Wen Gunn' || person.name !== 'Bar') {

                        return true;

                    }

                })

            )

        );

    });

// --> [{"name": "Will Wen Gunn"}, {"name": "Foo"}]

与其说 Underscore.js 是 Model 框架,还不如说是 Model 操作库,Underscore.js 并没有封装 Class ,而是使用 JavaScript 原有的 Array, Object, Function 类型进行操作 (其中人们比较常用 Object 和 Function 来模拟 Class)

这种 Model 会比 利用 Object 或者 Function 来定义 Class 要实际,因为这样可以很好地对对象和对象集 (Collection) 进行管理和操作。




V - View


View 更直接点地说就是我们平时所构建的 HTML ,而 MVC 其实源自于 DHTML ,W3C 的解释是动态页面(Dynamic HTML),而我更认为是 Data to HTML。

而这个正是Mustache.js诞生的原因

{{Mustache}}


var person,

    tmpl-persons,

    proxy = new Eventproxy(),

    persons = function (data, tmpl) {

        $('body').append(

            Mustache.to_html(tmpl, data)

        );

    };

proxy.assign('data', 'tmpl', persons);

$.getJSON(location.origin + '/persons')

    .done(function (data) {

        persons = JSON.parse(data);

        /*

         * [ {Name: "Will Wen Gunn", Age: 15, Sex: "Man"},

         *   {Name: "Foo", Age: 15, Sex: "Man"},

         *   {Name: "Bar", Age: 15, Sex: "Man"} ]

         */

        proxy.trigger('data', data);

    });

$.get(location.origin + '/tmpls/persons.html')

    .done(function (data) {

        tmpl-persons = data;

        /*

         * {{#peoples}}

         *     {{Name}}

         *     {{Age}}

         *     {{Sex}}

         * {{/peoples}}

         */

        proxy.trigger('tmpl', tmpl);

    });

/*

 * Will Wen Gunn

 * 15

 * Man

 * Foo

 * 15

 * Man

 * Bar

 * 15

 * Woman

 */

这里使用到了朴灵小田同学的 EventProxy.js,相当好玩的一个小工具,但是发挥出来的作用很强阿。

它能让几个异步请求并行处理,最后集中处理。

https://github.com/JacksonTian/eventproxy

另外也还有一个来自国外的,类似的东西,叫Step,它也让异步函数分开,但是是串列的队列式,所以会产生阻塞,小问并不建议使用。




C - Controller


这个恐怕是争议最大的一块了,有人推崇jQuery,有人推崇YUI,有人推崇MooTools……

其实这个并没有什么太大关系,只要是有这样的能力的,哪种 JavaScript Library 都没所谓的。

我这里用jQuery把上面的这些M,V整合起来:
var Person = Backbone.Model.extent({

        sayHello: function () {

            alert('Hey, I`m ' + this.get('name') + '.');

            return this;

        },

        setName: function (name) {

            this.set({'name': name});

            alert('My name is ' + this.get('name') + '.');

            return this;

        }

    }),

    Persons  = Backbone.Collection.extend({

        model: Person,

        sayHello: function () {

            this.each(function (Person) {

                $('body').append('Hey, I`m ' + Person.get('name') + '.');

            });

        },

        sayName: function () {

            this.each(function (Person) {

                $('body').append('My name is ' + Person.get('name') + '.');

            });

        }

    });

var CNodejs = new Persons;

var persons,

    tmpl-persons;

$.get(location.origin + '/persons')

    .done(function (data) {

        persons = JSON.parse(data);

    })

    .get(location.origin + '/tmpls/persons.html')

    .done(function () {

        tmpl-persons = JSON.parse(data);

    });

CNodejs.add(persons.peoples);

$('body').append(

    Mustache.to_html(

        tmpl-persons,

        { peoples: CNodejs.toJSON() }

    )

);





Node.js MVC


M - Model, V - View


其实 Backbone.js, Underscore.js 和 Mustache.js 在 Node.js 上的用法是和前端一模一样的,所以我就不多介绍了。

C - Controller


来看看 Web.js 的 Router :
var urlRouter = {

        '^(\d{4})\/(\d{2})\/(\d{2})\/(.*)\.jpg': '$1-$2-$3-$4.jpg',

        'google': 'http://www.google.com',

        'iwillwen': 'http://www.iwillwen.com'

    },

    getRouter = {

        '^getsomthing': function(req, res, qs) {

            res.sendJSON(qs);

        },

        '^car': function(req, res, qs) {

            switch (qs.action) {

                case 'foo':

                    res.send('Your action is foo');

                    break;

                case 'bar':

                    res.send('Your action is bar');

                    break;

            }

        }

    },

    postRouter = {

        '^postsomthing': function(req, res, data) {

            res.sendJSON(qs);

        },

        '^car': function(req, res, data) {

            switch (data.action) {

                case 'foo':

                    res.send('Your action is foo');

                    break;

                case 'bar':

                    res.send('Your action is bar');

                    break;

            }

        }

    };



web.run(urlRouter, 80)

    .get(getRouter)

    .post(postRouter);



console.log('The app is running on http://localhost');

这个和Express有点区别。

如果结合数据库的 Node.js MVC,Web.js该怎么写呢
var web =require('webjs'),

    mongo = require('mongoskin'),

    Backbone = require('backbone'),

    Underscore = require('underscore'),

    eventproxy = require('EventProxy.js'),

    db = mongo.db('localhost:27017/blog'),

    posts = db.collection('posts'),

    metas = db.collection('metas'),



var urlRouter = {

        '^page/(\d)': 'page.html',

        '^(.*)': 'post.html'

    },

    getRouter = {

        'init': function (req, res, qs) {

            var proxy = new eventproxy.EventProxy(),

            init = function (title, description, posts) {

                    var obj = {

                        title: title,

                        description: description,

                        posts: posts

                    };

                    res.sendJSON(obj);

                };

            proxy.assign('title', 'description', 'posts', init);

            metas.findOne({type: 'title'}, function (err, title) {

                proxy.trigger('title', title);

            });

            metas.findOne({type: 'description'}, function (err, description) {

                proxy.trigger('description', description);

            });

            posts.findTop10(function (err, posts) {

                proxy.trigger('posts', posts);

            });

        },

        'getPost': function (req, res, qs) {

            posts.findOne(qs, function (err, post) {

                res.sendJSON(post);

            });

        }

    },

    postRouter = {

        'setMeta': function (req, res, data) {

            metas.update(

                {type: data.type},

                data,

                {upsert: true},

                function (err) {

                    if (err) return res.send('Set failed.

' + err);

                    res.send('Set successed.');

                }

            );

        },

        'post': function (req, res, data) {

            posts.update(

                {title: data.title},

                data,

                {upsert: true},

                function (err) {

                    if (err) return res.send('Post failed.

' + err);

                    res.send('Post successed');

                }

            );

        }

    };

web.run(urlRouter, 80)

    .get(getRouter)

    .post(postRouter);





最后来讲讲

Web.js between client and server


来看看 Web.js for client (仍在编写中) 的用法
(function ($) {

    //loaded /js/web-client.js

    var getRouter = {

        'getsomething' : function () {

            var proxy = new Eventproxy(),

                post = function (data, tmpl) {

                    $('body').append(

                        Mustache.to_html(tmpl, data)

                    );

                };

            proxy.assign('data', 'tmpl', init);

            web.getData('post', {}, function (data) {

                proxy.trigger('data', data);

            });

            web.getTmpl('post', function (tmpl) {

                proxy.trigger('tmpl', tmpl);

            });

        }

    };

    web.conn(location.origin)

        .get(getRouter);

})(jQuery);





这时候大家可能会问了,Web.js 的 MVC 究竟异样在哪里呢?

前端 MVC 的 M 其实和后端 MVC 的 M 本来是不可能一起使用的,因为如果由后端进行模板渲染,前端就没有渲染的必要,那么前端 MVC就不成立了。同理,如果让前端进行模板渲染,后端也就不存在 MVC 的概念。

如果要前后端的 MVC 同时存在要怎么做呢,其实很简单,就是让客户端进行性能·评估。

比如说 IE6、7 这样的低性能浏览器,Web.js for client 会让服务器先进行 Data to HTML 渲染,然后传输再到客户端,如果是Chrome,FireFox,Safari 和 Opera 等高性能浏览器,则选择在客户端进行渲染,减轻传输荷载。

另外 Web.js 默认会开启缓存应用加速机制 (DOM Storage,Cookies,Buffer,Object……),让一部分数据先存入缓存,让短时间内再次发出的请求从缓存中获取。减少 LAN 资源和数据库资源的损耗。

JavaScript 是一门建立在静态页面上的动态脚本语言,Ajax的普及和发展,使它完全可以完成一些静态页面做不到的事情,比如像PHP自身的文件响应机制 (相比这也是 PHP 吸引人的一个终于优点)。

上面的这一段代码就演示了一个静态页面通过 Web.js 进行 URL action router 识别,并向服务器请求数据和模板,然后在 DOM 中插入渲染得到的 HTML。



两个 Web.js 之间是可以无缝对接的,开发者无须设置太多。

当然 Web.js for client 也是支持 Express 等其他 Server-side 开发框架的。




好,最后来放一个完整的 Web.js MVC Router 代码
//server.js

var web =require('webjs'),

    mongo = require('mongoskin'),

    Backbone = require('backbone'),

    Underscore = require('underscore'),

    eventproxy = require('EventProxy.js'),

    db = mongo.db('localhost:27017/blog'),

    posts = db.collection('posts'),

    metas = db.collection('metas'),



var urlRouter = {

        '^(.*)': 'page.html'

    },

    getRouter = {

        'init': function (req, res, qs) {

            var proxy = new eventproxy.EventProxy(),

                init = function (title, description, posts) {

                    var obj = {

                        title: title,

                        description: description,

                        posts: posts

                    };

                    if (qs.render) {

                        res.send(

                            web.render('init', obj)

                        );

                    } else {

                        res.sendJSON(obj);

                    }

                };

            proxy.assign('title', 'description', 'posts', init);

            metas.findOne({type: 'title'}, function (err, title) {

                proxy.trigger('title', title);

            });

            metas.findOne({type: 'description'}, function (err, description) {

                proxy.trigger('description', description);

            });

            posts.findTop10(function (err, posts) {

                proxy.trigger('posts', posts);

            });

        },

        'getpost': function (req, res, qs) {

            posts.findOne(qs ,function (err, post) {

                if (qs.render) {

                    res.send(

                        web.render('post', post)

                    );

                } else {

                    res.sendJSON(post);

                }

            });

        }

    };

web.run(urlRouter, 80)

    .get(getRouter)

    .set('tmplDir', 'tmpls');



//page.html - client.js

(function ($) {

    var getRouter = {

        '/' : function () {    //init

            var proxy = new Eventproxy(),

                init = function (data, tmpl) {

                    $('body').append(

                        Mustache.to_html(tmpl, data)

                    );

                };

            proxy.assign('data', 'tmpl', init);

            web.getData('init', {}, function (data) {

                proxy.trigger('data', data);

            });

            web.getTmpl('init', function (tmpl) {

                proxy.trigger('tmpl', tmpl);

            });

        }

        '^(.*)' : function (action) {    // action --> (.*)

            var proxy = new Eventproxy(),

                post = function (data, tmpl) {

                    $('body').append(

                        Mustache.to_html(tmpl, data)

                    );

                };

            proxy.assign('data', 'tmpl', init);

            web.getData('post', {title: action}, function (data) {

                proxy.trigger('data', data);

            });

            web.getTmpl('post', function (tmpl) {

                proxy.trigger('tmpl', tmpl);

            });

        }

    };

    web.conn(location.origin)

        .get(getRouter)

})(jQuery);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值