Home  >  Article  >  Web Front-end  >  Introduction to the use of View-Model in JavaScript_javascript skills

Introduction to the use of View-Model in JavaScript_javascript skills

WBOY
WBOYOriginal
2016-05-16 18:03:331511browse

构成
这是一个十分常见的微博列表页面,类似于新浪微博。上周末,在心无旁骛情况下,一共用了5个对象,产出400行代码,实践出一种代码组织模式。

使任务轻松完成的代码有4个方面的要素组成:

要素 组成
模型 Reply、Forward
视图 CommentEditor、ReplyList、ForwardList
模板 jQuery.tmpl
异步任务 jQuery.Deferred
Part introduction
Model
The model is only related to data. It can generate, filter, save, verify data, and that's all.

As shown in the following example, when the message model calls the save method, it only receives JSON parameters and only returns an asynchronous task. In actual processing, it does not matter whether the result is synchronous or asynchronous.
The reason for validation here is that it is an open object and is the last door to interaction with the server.
In addition, it does not handle validation failures itself - it is selectively handled when called by the view, and a message may pop up or simply ignored and retried.
Copy code The code is as follows:

// Message model
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 : 'Think Just say it', sourceid : 1001 }
create : function(data) {
// promise
var dfd = $.Deferred(), now = $.now();
if( (now - this.create.timestamp)/1000 < 10 ){
dfd.reject({message:'You posted too fast, take a break',type:'warn'})
} else if(!data || !data.sourceid){
dfd.reject({message:'illegal operation',type:'error'})
}else if(!data.content){
dfd.reject({message:'Comment content cannot be empty',type:'warn'})
}else{
this.create.timestamp = now;
dfd = $.post(' /ajax/blog/reply/create',data);
}
return dfd.promise();
}
};
Reply.create.timestamp = Forward.create.timestamp = $.now() - 1e4;

View
A view is the visible part of the browser page. Each view object contains an associated jQuery object as a property (instance.$el ), similar to the DOM container in UI components. The

view also has two consistent methods: The

render method is used to get data from the model and render the data to the HTML page according to the defined template.
The activate method is used to activate the view and bind related DOM events. All events are delegated to $el at most.
In this example, CommentEditor is the parent view, ReplyList and ForwardList are two subviews displayed mutually, and the parent and subviews save references to each other.
Copy code The code is as follows:

// Reply list view
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))
}
// ...
}

// Comment editor view
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);
// Forwarding and commenting at the same time
$.when(task_r,task_f). then(function(t1,t2) {
//Save successfully, update view or close
}, function(data) {
// Model validation error, or remote server error
Sys.info (data.message,data.type);
});
return self;
},
switchView : function(type) {
// Switch subview
var view_opt = {el:this.$sublist.empty(),parent:this};
if(type === 'reply'){
$label.show();
this.$submit. val('Comment');
this.sublist = new ReplyList(view_opt).render();
}else{
$label.hide();
this.$submit.val( 'Forward');
this.sublist = new ForwardList(view_opt).render();
}
}
// ...
}

Template
Template can eliminate tedious and ugly string splicing. Its function is to generate HTML fragments directly from js objects.

You can directly traverse objects in the template and apply predefined functions to format some data, such as the time function nicetime:
Copy code The code is as follows:

// Reply list template
var tpl_reply_list = '

    {{each list}}

  • ${name}:

    ${ content}


    Delete

  • {{/each}}
';

Asynchronous task
The literal translation of Deferred Object is delayed object, but It is more appropriate to understand it as an asynchronous task. Asynchronous tasks can eliminate multiple layers of nested callbacks, making code writing and reading more convenient.

From the above model and view code, it is obvious that after using asynchronous tasks, the code becomes more flat.

$.Deferred method creates a new two-way task queue: success callback function queue and failure callback function queue; the status of the task is also divided into two types: success and failure. You can use isResolved or isRejected to check the task respectively. The current status of the task, use resolve or reject to modify the task status.

The promise method returns a read-only copy of the task, and the task status cannot be modified on this copy. There is no doubt that models should always return only promise objects. (Note: The read-only copy can still call the promise method again to return the read-only copy)

In the Reply.create method, it can better handle custom asynchronous tasks instead of directly returning the native ajax asynchronous Task:
Copy code The code is as follows:

// 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||'Get failed',type:'error'});
}
})
.fail(function() {
dfd.reject({message:'Service is temporarily unavailable',type:'error'})
});

Purpose and Conclusion
Why is it broken up like this?

Gains: Maintainability, clear API calls, elimination of if statements above the second level, elimination of callback statements above the second level, and each function controlled within twenty lines.

Result: There is no excessive duplication of code, all functions are packaged.
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn