資源:
backbone中文檔
underscore中文檔
一个实现了web前端MVC模式的JS库
M : model (模型)
V : view (试图)
C : controller (控制器)
就是把模型与视图分离,通过控制器来连接他们
模塊:
Events : 事件驱动方法
Model : 数据模型
Collection : 模型集合器
Router : 路由器(hash)
History : 开启历史管理
Sync : 同步服务器方式
View : 试图(含事件行为和渲染页面)
1)直接創建對像:
/*
var models = new Backbone.Collection;
var views = new Backbone.View;
*/
var model = new Backbone.Model;
model.set('name','hello')
console.log(model.get('name'));
2)给构造函数添加实例方法和静态方法
var m_1 = new Backbone.Model({'name':'hello'})
var m_2 = new Backbone.Model({'name':'hi'})
var coll = new Backbone.Collection()
coll.add(m_1)
coll.add(m_2)
console.log(JSON.stringify(coll)); // 對象解析出字符串;
//Backbone.Model表示模型的構造函數,extend參數 ({json實例方法},{json靜態方法})
var M = Backbone.Model.extend({
aaa:function(){
console.log(123);
}
},{
bbb: function () {
console.log(456);
}
})
var model = new M
model.aaa() //實例方法使用實例調用;
M.bbb(); //靜態使用構造函數直接調用;即相當於多了一個命名空間而已;
//設置默認值:
var M = Backbone.Model.extend({
defaults:{
name:'hello'
}
})
var mo_= new M;
console.log(mo_.get('name'));
3)继承操作
var M = Backbone.Model.extend({
aaa: function () {
console.log('abc');
}
},{
bbb: function () {
console.log('def');
}
})
var ChildM = M.extend();
var mo = new ChildM
mo.aaa()
ChildM.bbb()
4)自定义事件
(function () {
var M = Backbone.Model.extend({
defaults:{
name:'hello'
},
initialize:function(){
this.on('change', function () {
console.log('onchange觸發了');
})
}
})
var model = new M
model.set('name','hi')
})();
//指定key值觸發;
(function () {
var M = Backbone.Model.extend({
defaults:{
name:'hello'
},
initialize:function(){
this.on('change:name', function (model) { //不同的key值觸發;
console.log(model);
})
}
})
var model = new M
model.set('name','hi')
})();
//1、創建模型對像
//2、創建視圖對像,直接在視圖對象裏傳參,指定模型對像,即連接在一起;
//3、對模型修改時,即會觸發視圖對象;
var M = Backbone.Model.extend({
defaults: {
name: 'hello'
}
});
var V = Backbone.View.extend({
initialize: function () {
this.listenTo(this.model, 'change', this.show);
},
show: function (model) {
$('body').append('<div>' + model.get('name') + '</div>')
}
});
var m = new M; //1、創建模型對像
var v = new V({model: m}); //2、創建視圖對像,直接在視圖對象裏傳參,指定模型對像,即連接在一起;
m.set('name', 'hi') //3、對模型修改時,即會觸發視圖對象;
5)數據與服務器
(function () {
Backbone.sync = function (method, model) {
console.log(method + ': ' + JSON.stringify(model));
model.id = 1;
}
var M = Backbone.Model.extend({
defaults:{
name:'hello'
},
url:'/user' // ajax提交,一定要指定好url ;
});
var m = new M;
m.save(); //把現在的模型對象保存到服務器上;
m.save({name:'hi'}); //修改
})();
(function () {
Backbone.sync = function (method, model) {
console.log(method + ': ' + JSON.stringify(model));
}
var C = Backbone.Collection.extend({
initialize: function () {
this.on('reset', function () {
console.log(123);
})
},
url:'/user' // ajax提交,一定要指定好url ;
});
var m = new C;
m.fetch() //讀取服務器數據;
})();
6)路由與歷史管理
(function () {
var Workspace = Backbone.Router.extend({
routes:{
'help': 'help',
'search/:query': 'search', //#search/任意字符;
'search/:query/p:page': 'search' //#search//kiwis/p7
},
help: function () {
console.log(1);
},
search: function (query,page) {
console.log(2);
}
})
var w = new Workspace
Backbone.history.start()
/*
* 地址後面加#help,彈1;
* 地址後面加#search/dfk 彈2
*
* */
})();
7)事件委託
所有的视图都拥有一个 DOM 元素(el 属性),即使该元素仍未插入页面中去。 视图可以在任何时候渲染,然后一次性插入 DOM 中去,这样能尽量减少 reflows 和 repaints 从而获得高性能的 UI 渲染。 this.el 可以从视图的 tagName, className, id 和 attributes 创建,如果都未指定,el 会是一个空 div。
(function () {
var V = Backbone.View.extend({
el:$('body'), //觸發的委託人;
events:{
'click input':'aaa',
'mouseover li':'bbb'
},
aaa: function () {
console.log(1111111);
},
bbb: function () {
console.log(2221222);
}
})
var veiw = new V;
})();
8)前端模板
$(function () {
var M = Backbone.Model.extend({
defaults:{
name:'hello'
}
})
var V = Backbone.View.extend({
initialize: function () {
this.listenTo(this.model,'change',this.show)
},
show: function (model) {
$('body').append(this.template(this.model.toJSON()))
},
template: _.template($('#template').html())
})
var m = new M;
var v = new V({model:m})
m.set('name','hdi')
})
調用:
<script type="text/template" id="template">
<% for(var i=0;i<5;i++) { %>
<div><%= name %></div>
<% } %>
</script>
大部分操作:
首先頁面上先對【數據進行修改】 ----> 數據修改包括【模型修改】或【集合修改】--->
當這兩個修改後---> 會觸發相應的【自定義事件】--->
自定義事件找到相應---> 【視圖】--->
回調函數更新視圖----> 視圖的更新通過前端模板獲取到,再生成到---->頁面;
一個模型和一個集合,一個模型對應一個視圖,集合對應大視圖;
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<script src="json2.js"></script>
<script src="jquery-1.11.1.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>
<script src="backbone.localStorage.js"></script>
<!--本地存,代替ajax-->
<body>
<div id="todoapp">
<header>
<h1>Todos</h1>
<input id="new-todo" type="text" placeholder="What needs to be done?">
</header>
<section id="main">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list"></ul>
</section>
<footer>
<a id="clear-completed">Clear completed</a>
<div id="todo-count"></div>
</footer>
</div>
<div id="instructions">
Double-click to edit a todo.
</div>
<div id="credits">
Created by
<br/>
<a href="http://jgn.me/">Jérôme Gravel-Niquet</a>.
<br/>Rewritten by: <a href="http://addyosmani.github.com/todomvc">TodoMVC</a>.
</div>
<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">Clear <%= done %> completed <%= done == 1 ? 'item' : 'items' %></a>
<% } %>
<div class="todo-count"><b><%= remaining %></b> <%= remaining == 1 ? 'item' : 'items' %> left</div>
</script>
<script>
// An example Backbone application contributed by
// [J茅r么me Gravel-Niquet](http://jgn.me/). This demo uses a simple
// [LocalStorage adapter](backbone-localstorage.html)
// to persist Backbone models within your browser.
// Load the application once the DOM is ready, using `jQuery.ready`:
$(function () {
// Todo Model
// ----------
// Our basic **Todo** model has `title`, `order`, and `done` attributes.
var Todo = Backbone.Model.extend({
// Default attributes for the todo item.
defaults: function () {
return {
title: "empty todo...title", //空默認值
order: Todos.nextOrder(), //集合中該加到什麼位置
done: false //開關,哪些保存,哪些未保存;
};
},
// Toggle the `done` state of this todo item.
toggle: function () { //保存開關的真假,如選擇,取消;
this.save({done: !this.get("done")});
}
});
// Todo Collection
// ---------------
// The collection of todos is backed by *localStorage* instead of a remote
// server.
var TodoList = Backbone.Collection.extend({ //對你集合
// Reference to this collection's model.
model: Todo, //指定模型;
// Save all of the todo items under the `"todos-backbone"` namespace.
localStorage: new Backbone.LocalStorage("todos-backbone"), //內步服務器方式;
// Filter down the list of all todo items that are finished.
done: function () {//哪些完成
return this.where({done: true});
},
// Filter down the list to only todo items that are still not finished.
remaining: function () { //哪些未完成;
return this.where({done: false});
},
// We keep the Todos in sequential order, despite being saved by unordered
// GUID in the database. This generates the next order number for new items.
nextOrder: function () { //找對應順序
if (!this.length) return 1;
return this.last().get('order') + 1;
},
// Todos are sorted by their original insertion order.
comparator: 'order' //默認排序方式;現在按order排序;
});
// Create our global collection of **Todos**.
var Todos = new TodoList; //創建集合
// Todo Item View
// --------------
// The DOM element for a todo item...
var TodoView = Backbone.View.extend({ //創建視圖,針對一個模型的;即一條記錄
//... is a list tag.
tagName: "li", //視圖標籤
// Cache the template function for a single item.
template: _.template($('#item-template').html()), //針對一個模型的模板;
// The DOM events specific to an item.
events: { //視圖事件;
"click .toggle": "toggleDone", //點擊
"dblclick .view": "edit", //雙擊
"click a.destroy": "clear", //編輯完抬起保存
"keypress .edit": "updateOnEnter", //更新數據;
"blur .edit": "close" //光標消失時也保存
},
// The TodoView listens for changes to its model, re-rendering. Since there's
// a one-to-one correspondence between a **Todo** and a **TodoView** in this
// app, we set a direct reference on the model for convenience.
initialize: function () {
this.listenTo(this.model, 'change', this.render); //當模板改變時對應這個,相當於重新薰染視圖
this.listenTo(this.model, 'destroy', this.remove); //數據刪除時對應的回調;
},
// Re-render the titles of the todo item.
render: function () { //更新視圖,通過模板形式;
this.$el.html(this.template(this.model.toJSON()));
this.$el.toggleClass('done', this.model.get('done'));
this.input = this.$('.edit');
return this;
},
// Toggle the `"done"` state of the model.
toggleDone: function () { //是否保存;
this.model.toggle();
},
// Switch this view into `"editing"` mode, displaying the input field.
edit: function () { //編輯時徊claa一個輸入框
this.$el.addClass("editing");
this.input.focus();
},
// Close the `"editing"` mode, saving changes to the todo.
close: function () {
var value = this.input.val();
if (!value) {
this.clear();
} else {
this.model.save({title: value}); //編輯完成後保存數據,
this.$el.removeClass("editing"); //去掉編輯框;
}
},
// If you hit `enter`, we're through editing the item.
updateOnEnter: function (e) {
if (e.keyCode == 13) this.close(); //回車時調用close
},
// Remove the item, destroy the model.
clear: function () {
this.model.destroy();
}
});
// The Application
// ---------------
// Our overall **AppView** is the top-level piece of UI.
var AppView = Backbone.View.extend({ //這個視圖針對一整個集合;
// Instead of generating a new element, bind to the existing skeleton of
// the App already present in the HTML.
el: $("#todoapp"), //事件操作都綁定到父級上
// Our template for the line of statistics at the bottom of the app.
statsTemplate: _.template($('#stats-template').html()),
// Delegated events for creating new items, and clearing completed ones.
events: {//加事件;
"keypress #new-todo": "createOnEnter",
"click #clear-completed": "clearCompleted",
"click #toggle-all": "toggleAllComplete" //全選按鈕 ;
},
// At initialization we bind to the relevant events on the `Todos`
// collection, when items are added or changed. Kick things off by
// loading any preexisting todos that might be saved in *localStorage*.
initialize: function () { //視圖初始化
this.input = this.$("#new-todo"); //獲取元素
this.allCheckbox = this.$("#toggle-all")[0];
this.listenTo(Todos, 'add', this.addOne);
this.listenTo(Todos, 'reset', this.addAll); //綁定事件;
this.listenTo(Todos, 'all', this.render); //這個集合什麼操作都會發生事件;
this.footer = this.$('footer');
this.main = $('#main');
Todos.fetch(); //更新本地數據;
},
// Re-rendering the App just means refreshing the statistics -- the rest
// of the app doesn't change.
render: function () { //視圖渲染;
var done = Todos.done().length;
var remaining = Todos.remaining().length;
if (Todos.length) {
this.main.show();
this.footer.show();
this.footer.html(this.statsTemplate({done: done, remaining: remaining}));
} else {
this.main.hide();
this.footer.hide(); //生成到對應的頁腳;
}
this.allCheckbox.checked = !remaining;
},
// Add a single todo item to the list by creating a view for it, and
// appending its element to the `<ul>`.
addOne: function (todo) { //加一條時對應的回調;
var view = new TodoView({model: todo});
this.$("#todo-list").append(view.render().el);
},
// Add all items in the **Todos** collection at once.
addAll: function () {
Todos.each(this.addOne, this);
},
// If you hit return in the main input field, create new **Todo** model,
// persisting it to *localStorage*.
createOnEnter: function (e) { //回車時,創建 添加到集合中,集合即可對應渲染;
if (e.keyCode != 13) return;
if (!this.input.val()) return;
Todos.create({title: this.input.val()});
this.input.val('');
},
// Clear all done todo items, destroying their models.
clearCompleted: function () {
_.invoke(Todos.done(), 'destroy');
return false;
},
toggleAllComplete: function () {
var done = this.allCheckbox.checked;
Todos.each(function (todo) {
todo.save({'done': done});
});
}
});
// Finally, we kick things off by creating the **App**.
var App = new AppView;
});
/*
大部分操作: 首先頁面上先對數據進行修改 ,數據修改包括模型修改或集合修改,當這兩個修改後 會觸發相應的自定義事件;自定義事件找到相應的視圖;回調函數更新視圖;視圖的更新通過前端模板獲取到,再生成到頁面;
* 一個模型和一個集合,一個模型對應一個視圖,集合對應大視圖;
*
*
*
* */
</script>
<style>
html,
body {
margin: 0;
padding: 0;
}
body {
font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #eeeeee;
color: #333333;
width: 520px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
}
#todoapp {
background: #fff;
padding: 20px;
margin-bottom: 40px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0;
-webkit-border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-ms-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
}
#todoapp h1 {
font-size: 36px;
font-weight: bold;
text-align: center;
padding: 0 0 10px 0;
}
#todoapp input[type="text"] {
width: 466px;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
padding: 6px;
border: 1px solid #999999;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
}
#main {
display: none;
}
#todo-list {
margin: 10px 0;
padding: 0;
list-style: none;
}
#todo-list li {
padding: 18px 20px 18px 0;
position: relative;
font-size: 24px;
border-bottom: 1px solid #cccccc;
}
#todo-list li:last-child {
border-bottom: none;
}
#todo-list li.done label {
color: #777777;
text-decoration: line-through;
}
#todo-list .destroy {
position: absolute;
right: 5px;
top: 20px;
display: none;
cursor: pointer;
width: 20px;
height: 20px;
background: url(destroy.png) no-repeat;
}
#todo-list li:hover .destroy {
display: block;
}
#todo-list .destroy:hover {
background-position: 0 -20px;
}
#todo-list li.editing {
border-bottom: none;
margin-top: -1px;
padding: 0;
}
#todo-list li.editing:last-child {
margin-bottom: -1px;
}
#todo-list li.editing .edit {
display: block;
width: 444px;
padding: 13px 15px 14px 20px;
margin: 0;
}
#todo-list li.editing .view {
display: none;
}
#todo-list li .view label {
word-break: break-word;
}
#todo-list li .edit {
display: none;
}
#todoapp footer {
display: none;
margin: 0 -20px -20px -20px;
overflow: hidden;
color: #555555;
background: #f4fce8;
border-top: 1px solid #ededed;
padding: 0 20px;
line-height: 37px;
-webkit-border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-ms-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
}
#clear-completed {
float: right;
line-height: 20px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
color: #555555;
font-size: 11px;
margin-top: 8px;
margin-bottom: 8px;
padding: 0 10px 1px;
cursor: pointer;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
-ms-border-radius: 12px;
-o-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-ms-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
}
#clear-completed:hover {
background: rgba(0, 0, 0, 0.15);
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-ms-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
}
#clear-completed:active {
position: relative;
top: 1px;
}
#todo-count span {
font-weight: bold;
}
#instructions {
margin: 10px auto;
color: #777777;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#instructions a {
color: #336699;
}
#credits {
margin: 30px auto;
color: #999;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#credits a {
color: #888;
}
</style>
</body>
</html>
<script>
var f = 1;
document.getElementById('tdosclick').onclick = function(){
if(f){
document.getElementById('tdos').style.display = 'block';
}
else{
document.getElementById('tdos').style.display = 'none';
}
f = !f;
}
</script>