backbone实例Todo源码赏析

作者:zccst
Todo实例花了我两天多的事件,为了下次再忘记,决定记录下来:

$(function(){
/******************** 模型-集合 ********************/
var Todo = Backbone.Model.extend({
defaults:function(){//defaults是函数
return {title:'apple', order:Todos.nextOrder(), done:false};
},
initialize:function(){
if(!this.get("title")){ this.set({title:this.defaults().title}); }
},
validate:function(){
//console.log(this);//alert('validate');
},
toggle:function(){//每次取反
//model变,那么Todos也变,触发Collection的all事件(不是reset)
this.save({done:!this.get('done')});
}
});

var TodoList = Backbone.Collection.extend({
model:Todo,
localStorage:new Backbone.LocalStorage("todos-backbone-my"),//存储
//默认没有,如果定义了,则被用来维护集合在正确的顺序
comparator:function(todo){
return todo.get("order");//使用order作为排序基准。order
},
done:function(){//选择done字段为true的集合
//filter是underscore提供的
return this.filter(function(todo){return todo.get("done");});
},
remaining:function(){
//underscore提供,排除this中的this.done()元素列表
return this.without.apply(this, this.done());
},
nextOrder:function(){//返回该元素的下一个元素序号
if(!this.length) return 1;
//underscore提供,获取最后一个元素的order值再加1
return this.last().get("order") + 1;
}
});
var Todos = new TodoList;//创建一个名叫Todos的全局集合列表

/******************** 视图 ********************/
var TodoView = Backbone.View.extend({
tagName : "li",//el:"todo-list",
template:_.template($("#item-template").html()),
events:{
'click .toggle' : 'toggleDone', //点击切换,选中状态
'dbclick .view' : 'edit', //双击编辑
'blur .edit' : 'close', //双击编辑后,失去焦点
'keypress .edit' : 'updateOnEnter',//双击编辑后,按enter键 编辑成功
'click a.destroy': 'clear' //点击删除
},
initialize:function(){//model也就两个事件
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'destroy', this.remove);
},
render:function(){
//console.log(this.model);
this.$el.html(this.template(this.model.toJSON()));
this.$el.toggleClass("done",this.model.get("done"));
this.input = $(".edit");//始终指向当前被点击的行
return this;
},
toggleDone:function(){//点击切换选中状态
this.model.toggle();
},
edit:function(){//双击编辑
this.$el.addClass("editing");
this.input.focus();
},
close:function(){//双击编辑后,input失去焦点
var value = this.input.val();
if(!value){
this.clear();
}else{
this.model.save({title:value});//直接save,不需要set啊
this.$el.removeClass("editing");
}
},
updateOnEnter:function(e){//双击编辑后,按enter键 编辑成功
if(e.keyCode == 13) this.close();
},
clear:function(){//点击删除
this.model.destroy();//先触发destroy,后触发change事件
}
});

var AppView = Backbone.View.extend({
//el:"#todoapp",el表示element,如果是id,需要#ID
el:$("#todoapp"),
statsTemplate : _.template($("#stats-template").html()),
events:{//events是对象
'keypress #new-todo' : 'createOnEnter', //创建新的
'click #toggle-all' : 'toggleAllComplete', //全选
'click #clear-completed' : 'clearCompleted' //清空
},
initialize:function(){
this.input = this.$("#new-todo");
this.allCheckbox = this.$("#toggle-all")[0];
//触发add事件的方法 :create, fetch, add, set
this.listenTo(Todos, 'add', this.addOne);
//this.listenTo(Todos, 'reset', this.addAll);//触发reset :reset
//只控制了footer模板,查询计算已选和未选个数
//this.listenTo(Todos, 'all', this.render);
this.listenTo(Todos, 'change', this.render);
this.listenTo(Todos, 'add', this.render);
this.listenTo(Todos, 'remove', this.render);
this.footer = this.$("footer");
this.main = this.$("#main");
//化学效应,先驻足半小时,过一遍backbone的事件监听流程
Todos.fetch();//没触发change,reset,remove事件,触发了add事件。{reset:true}触发reset事件
},
render:function(){//更新当前任务列表的状态
var done = Todos.done().length; //已选中的集合
var remaining = Todos.remaining().length; //未选中的集合
if( Todos.length ){ //Todos.length全部的集合
this.main.show();
this.footer.show();
this.footer.html(this.statsTemplate({done:done,remaining:remaining}));
}else{
this.main.hide();
this.footer.hide();
}
//console.log(done,remaining);
this.allCheckbox.checked = !remaining;
},
createOnEnter:function(e){//在events中绑定,所以参数是event
if(e.keyCode != 13) return;
if(!this.input.val()) return;
//触发集合的add事件(绑定了addOne方法)
Todos.create({'title':this.input.val()});
this.input.val("");
},
toggleAllComplete:function(){
var done = this.allCheckbox.checked;
Todos.each(function(todo){ todo.save({'done':done}); });
},
clearCompleted:function(){
//清除所有被选中的(done:true的)
//_.invoke(Todos.done(), 'destroy');
var arr = Todos.done();for(var item in arr){ arr[item].destroy();};//替换
return false;
},
addOne:function(todo){//在initialize中绑定,所以参数是model
var view = new TodoView({model:todo});
//Todo的render方法必须主动调
this.$("#todo-list").append(view.render().el);
},
addAll:function(){
Todos.each(this.addOne, this);
}
});
var AppView = new AppView();
});



批注:AppView中initialize的add, change, remove 加起来基本可以相当于all事件了。

reset的使用场景:
1,调用fetch()方法时加了{reset:true}时触发reset事件
2,直接reset({...});时触发reset事件





Todos演示

















    双击编辑一个todo.



    某某创建。

    Rewritten by: TodoMVC.












    如果您觉得本文的内容对您的学习有所帮助,您可以微信:
    [img]http://dl2.iteye.com/upload/attachment/0109/0668/fb266dfa-95ca-3d09-b41e-5f04a19ba9a1.png[/img]

    你可能感兴趣的:(backbone等框架,JavaScript,backbone,todo)