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事件



<div id="todoapp">
<header>
<h1>Todos演示</h1>
<input id="new-todo" type="text" placeholder="请输入您想做的事情?">
</header>

<section id="main">
<!--for 属性规定 label 与哪个表单元素绑定-->
<input id="toggle-all" type="checkbox">
<label for="toggle-all">全选</label>

<ul id="todo-list"></ul>
</section>

<footer>
<a id="clear-completed">全部清空</a>
<div id="todo-count"></div>
</footer>
</div>

<div id="instructions">
双击编辑一个todo.
</div>

<div id="credits">
由<a href="http://www.sogou.com">某某</a>创建。
<br />Rewritten by: <a href="http://addyosmani.github.com/todomvc">TodoMVC</a>.
</div>


<!-- Templates -->
<!-- 每一项的模板 -->
<script type="text/template" id="item-template">
<div class="view">
<input class="toggle" type="checkbox" <%= done ? 'checked="checked"' : '' %> />
<label><%- title %></label>
<a class="destroy"></a>
</div>
<input class="edit" type="text" value="<%- title %>" />
</script>

<!-- 底部模板 -->
<script type="text/template" id="stats-template">
<% if (done) { %>
<a id="clear-completed"> 有 <%= done %> 个被选中,立即清除 </a>
<% } %>
<div class="todo-count">还有 <b><%= remaining %></b> 个未被选中</div>
</script>



如果您觉得本文的内容对您的学习有所帮助,您可以微信:
[img]http://dl2.iteye.com/upload/attachment/0109/0668/fb266dfa-95ca-3d09-b41e-5f04a19ba9a1.png[/img]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值