JavaScript中的View-Model

來源:互聯網
上載者:User
文章目錄
  • 模型
  • 視圖
  • 模板
  • 非同步任務
構成

這是一個十分常見的微博列表頁面,類似於新浪微博。上周末,在心無旁騖情況下,一共用了5個對象,產出400行代碼,實踐出一種程式碼群組織模式。

使任務輕鬆完成的代碼有4個方面的要素組成:

要素 組成
模型 Reply、Forward
視圖 CommentEditor、ReplyList、ForwardList
模板 jQuery.tmpl
非同步任務 jQuery.Deferred
分部介紹模型

模型只與資料有關,它能夠產生、過濾、儲存、驗證資料,並且僅此而已。

如下例,留言模型在調用儲存方法時,只接收JSON參數,並且只返回一個非同步任務,實際處理時同步或非同步返回結果並不重要。

在此進行的驗證的原因是,它是一個開放的對象,是與伺服器互動的最後一道門檻。

另外,它本身也不處理驗證失敗的情況——由視圖調用時選擇性地處理,可能會彈出一個訊息提示或直接忽略再進行重試。

// 留言模型var Reply = {    cache : {},    // { sourceid : id,page_size : 10,page_num : 1 }    fetch : function(data) {        return $.post('/ajax/blog/reply/list',data||{}).success(function(resp) {            resp.ok && resp.list &&            $.each(resp.list,function(k,v) {                return Reply.cache[v.id] = v;            });        });    },    // filter('name','king')    filter : function(prop,val) {        return $.grep(this.cache,function(r){ return r[prop] === val });    },    // { content : '想說就說',sourceid : 1001 }    create : function(data) {        // promise        var dfd = $.Deferred(), now = $.now();        if( (now - this.create.timestamp)/1000 
視圖

視圖是瀏覽器頁面上的可視部分,每個視圖對象含有一個關聯的 jQuery 對象作為屬性(instance.$el),類似於UI組件中的DOM容器。

視圖還有兩個一致的方法:

  • render 方法用於從模型擷取資料,並且根據定義好的模板將資料渲染到HTML頁面上。
  • activate 方法用於啟用視圖,同時綁定相關的DOM事件,所有事件至多委託到$el為止。

這個樣本中,CommentEditor是父視圖,ReplyList和ForwardList是互斥顯示的兩個子視圖,父子視圖之間相互儲存引用。

// 回複列表視圖var ReplyList = function(options) {    var opt = this.opt = $.extend({        el : '',        parent : null    },options||{});    this.parent = opt.parent;    this.$el = $(opt.el);    this.activate(); };ReplyList.prototype = {    render : function() {        var self = this;        Reply.fetch({            page_size : 10, page_num : 1,            sourceid : self.parent.getBlogId()        })        .done(function(data) {            self.$el.html( self.$list = $.tmpl(tpl_reply_list,data) );        });        return self;    },    activate : function() {        this.$el.delegate('a.del',$.proxy(this.del,this))    }    // ...}// 評論編輯器視圖CommentEditor.prototype = {    activate    : function() {        this.$el.delegate('a.save',$.proxy(this.save,this))    },    save    : function() {        var self = this, data = { content : self.getContent(),sourceid : self.getBlogId() };        var task_r = Reply.create(data);        var task_f = Forward.create(data);        // 轉寄、評論同時進行        $.when(task_r,task_f).then(function(t1,t2) {            // 儲存成功,更新視圖或關閉        },function(data) {            // 模型驗證出錯,或遠程伺服器錯誤            Sys.info(data.message,data.type);        });        return self;    },    switchView  : function(type) {        // 切換子視圖        var view_opt = {el:this.$sublist.empty(),parent:this};        if(type === 'reply'){            $label.show();            this.$submit.val('評論');            this.sublist = new ReplyList(view_opt).render();          }else{            $label.hide();            this.$submit.val('轉寄');            this.sublist = new ForwardList(view_opt).render();        }    }    // ...}
模板

模板可以消除繁瑣、醜陋的字串拼接,它的作用是能夠直接由js對象產生HTML片斷。

模板中可以直接遍曆對象,套用預定義的函數,來對一些資料進行格式化,比如時間函數nicetime:

// 回複列表模板var tpl_reply_list = '<ul class="ui-reply-list">\{{each list}}\<li data-id="${id}">\    <a class="name" href="/${userid}">${name}:</a>\    <p>${content}</p>\    <time pubdate>${nicetime(timestamp)}</time><a class="del" href="javascript:;">刪除</a>\</li>\{{/each}}\</ul>';
非同步任務

Deferred Object 的直譯是延遲物件,但是理解成非同步任務更為恰當。非同步任務能夠消除多層嵌套的回調,讓代碼書寫和閱讀更為便利。

從上面的模型和視圖的代碼中可以明顯地看出,使用了非同步任務之後,代碼變得更加平面化了。

$.Deferred 方法建立的是一個雙向任務隊列:成功回呼函數隊列和失敗回呼函數隊列;任務的狀態也分為兩種:成功和失敗,分別可以用isResolved或isRejected來檢查任務的目前狀態、用resolve或reject修改任務狀態。

promise 方法返回任務的唯讀副本,此副本上不能修改任務狀態。毫無疑問,模型應該始終只返回 promise 對象。(註:唯讀副本仍然可以再次調用 promise 方法再次返回唯讀副本)

在Reply.create方法中,能夠更好地處理自訂的非同步任務,而不是直接返回原生的ajax非同步任務:

// var dfd = $.Deferred();$.post('/ajax/blog/reply/create',data).success(function(json) {    if(json && json.ok){        dfd.resolve(json.list);    }else{        dfd.reject({message:json.message||'擷取失敗',type:'error'});    }}).fail(function() {    dfd.reject({message:'服務暫時不可用',type:'error'})});
目的及結論

為什麼拆散成這樣?

收穫:可維護性,清晰的API調用、消除二層以上的if語句、消除二層以上的回調語句、每個函數控制在二十行之內。

結果:沒有過多的重複代碼,所有的功能都被打包好了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.