CanJS基础教程
来源:互联网 发布:js date获取日期 编辑:程序博客网 时间:2024/05/02 04:56
1 加载Loading CanJS
CanJS加载方式:
- 直接引用js库(canjs官网可以定制插件一起打包下载) l
- AMD(requirejs)
<html><head> <title>CanJS Tutorial</title></head><body> <scriptsrc="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script> <scriptsrc="http://canjs.com/release/latest/can.jquery.js"></script> <scripttype="text/javascript"> $(function(){ // Your tutorial code here }); </script></body></html>
2 Constructor Functions
can.Construct可以简单的理解为CanJs的基类, Observables, Models, Controls都是基它的.
创建自己的construct,通过调用can.Construct.extend方法,并且传递两个参数,第一个参数是它的静态属性,第二个参数是对象(原型)属性.如果只传了一个参数,那么该参数当作对象(原型)属性.
var PrivateTodo = Todo.extend({},{ isSecret: function() { return true; }});var p = new PrivateTodo();p.allowedToEdit(); // false
2.1 初始化
在第二个参数中的init方法,创建一个实例时会调用.
var Todo = can.Construct.extend({ init: function(owner) { this.owner = owner; }, allowedToEdit: function() { return true; }});var t = new Todo("me");t.owner; // 'me'
2.2 继承
在init中调用父类的init方法(斜体部分)
var PrivateTodo = can.Construct.extend({ init: function(owner, isShared) { *can.Construct.prototype.init.apply(this, arguments);* this.isShared = isShared; }, allowedToEdit: function(){ return this.owner === "me" || this.isShared; }});
3 可监控的对象Observables
Observables:可以操作对象的数据并且可以监听数据的改变做相应的处理
Observables包含如下三种类型:
- can.Map - Used forObjects.
- can.List - Used for Arrays.
- can.compute - Used for values/compute.
其中can.Map和can.List是常用的Observable类型,Models和can.rout是基于can.Map.后面会讲到的can.Component的scope属性也是一个can.Map类型
创建一个Map需要传递一个对象(JSON)类型参数,创建一个List需要传递一个数组
var pagination=new can.Map({page:1, perPage:25, count:1388})pagination.attr('perPage');// 25var hobbies=new can.List(['programming','bball','party rocking']);hobbies.attr(2);// 'partying'
3.1 操作属性
Map和List使用attr()方法来读取、修改、添加属性操作,使用removeAttr()方法来删除属性操作
pagination.attr('perPage'); // 25pagination.attr('perPage',50);pagination.attr('perPage'); // 50pagination.attr({page:10, lastVisited:1});pagination.attr();// {page: 10, perPage: 50, count: 1388, lastVisited: 1}pagination.removeAttr('count');pagination.attr();// {page: 10, perPage: 50, lastVisited: 1}
3.2 事件监听
当一个Map类型对象使用attr()方法修改属性时会触发两个事件,一个change事件和一个与被修改的属性同名的事件,可以通过使用bind来监听这些事件,通过unbind去掉对应的监听
paginate.bind('change',function(event, attr, how, newVal, oldVal){attr; // 'perPage'how; // 'set'newVal;// 30oldVal;// 50});paginate.bind('perPage',function(event, newVal, oldVal){ newVal;// 30 oldVal;// 50});paginate.attr('perPage',30);
3.3 使用each遍历Map属性
paginate.each(function(val, key){ console.log(key+': '+ val);});// page: 10// perPage: 30// lastVisited: 1
3.4 扩展Map对象
Paginate= can.Map.extend({ limit:100, offset:0, count:Infinity, page:function(){ returnMath.floor(this.attr('offset')/this.attr('limit'))+1; }, next:function(){ this.attr('offset',this.attr('offset')+this.attr('limit')); }});var pageInfo=newPaginate();pageInfo.attr("offset")//-> 0pageInfo.next();pageInfo.attr("offset")//-> 100pageInfo.page() //-> 2
3.5 监控List对象 Observable Arrays
Can.List继承can.Map,所以他有Map的功能,同时还有一些其他的一些常用的方法,当这些方法修改了List,如下所示:
- indexOf, which looks for an item in a List.
- pop, which removes the last item from a List.
- push, which adds an item to the end of a List.
- shift, which removes the first item from a List.
- unshift, which adds an item to the front of a List.
- splice, which removes and inserts items anywhere in a List.
同时我们也可以对List做一些监听,常用的如下所示,详见API
- the change event fires onevery change to a List.
- the set event is fired when an element is set.
- the add event is firedwhen an element is added to the List.
- the remove event is firedwhen an element is removed from the List.
- the length event is firedwhen the length of the List changes.
3.6 监控计算 Computed values
Computedvalues(计算值,可读,可写,可监听),简单计算使用can.compute(value)创建,一样可以可读,可写,可监听
var age = can.compute(25), previousAge = 0;// read the Compute's valueage(); // 25// listen for changes in the Compute's valueage.bind('change', function(ev, newVal, oldVal) { previousAge = oldVal;});// set the Compute's valueage(26);age(); // 26previousAge; // 25
组合计算使用can.compute(getterFunction)创建
var name = new can.Map({ first: 'Alice', last: 'Liddell'});var fullName = can.compute(function() { // We use attr to read the values // so the compute knows what to listen to. return name.attr('first') + ' ' + name.attr('last');});var previousName = '';fullName(); // 'Alice Liddell'fullName.bind('change', function(ev, newVal, oldVal) { previousName = oldVal;});name.attr({ first: 'Allison', last: 'Wonderland'});fullname(); // 'Allison Wonderland'previousName; // 'Alice Liddell'
转换计算(Converted Computes)
// progress ranges from 0 to 1.var project = new can.Map({ progress: 0.3 });var progressPercentage = can.compute(function(newVal) { if(newVal !== undefined) { // set a value project.attr('progress', newVal / 100); } else { // get the value return project.attr('progress') * 100; }});percentage(); // 30// Setting percentage...percentage(75);// ...updates project.progress!project.attr('progress'); // .75
4 模型及数据交互
4.1 创建Model
使用can.Model,特定的静态方法与后台交互(RESTful API)。常用的有:
var Todo = can.Model({ findAll: 'GET /todos', findOne: 'GET /todos/{id}', create: 'POST /todos', update: 'PUT /todos/{id}', destroy: 'DELETE /todos/{id}'}, {});var dishesTask = new Todo({description: 'Do the dishes.'});
4.2 与服务交互
从服务中接受数据can.Model.findAll方法接收一组Model对象
Todo.findAll({},function(todos){ // todos is a can.Model.List of Todo Models.},function(xhr){ // handle errors});
can.Model.findOne同findAll一样,但只接收一个Model对象
update、create 、destroy
调用save方法时,如果该model有Id,则调用update,否则调用create
var shopping=newTodo({description:"Go grocery shopping."});shopping.save(function(saved){ // saved is the saved Todo saved.attr('description','Remember the milk.'); saved.save();});
调用destroy方法 删除一个model对象,调用destroy
var cats=newTodo({description:"Feed the cats."});cats.save(function(saved){ saved.destroy(function(destroyed){ // destroyed is the Todo that was destroyed });});
4.3 事件监听
因为Model也是一种特殊的Observes,也可以和其他的Observers一样 bind相同事件,使用Model.bind(eventType, handler(event, model))来监听某Model类型的事件,使用model.bind(eventType, handler(event))来监听具体的model对象的的事件
Model三种特殊事件:
- created, when an instance iscreated on the server.
- updated, when an instance isupdated on the server.
- destroyed, when an instance isdestroyed on the server.
var mop=newTodo({description:'Mop the floor.'});mop.bind('created',function(ev, created){ // created is the created Todo});mop.save();
也可以在Model类上bind上述三种事件,表示任何该类型的对象的操作(created、updated,destroyed)都会监听到
Todo.bind('created',function(ev, created){ // created is the created Todo});
4.4 Model Lists
ModelLists (provided by can.Model.List) are Lists whose items are Models. When one of aModel List’s elements are destroyed, that element is removed from the list.
Todo.findAll({}, function(todos) { todos.length; // 5 todos[0].destroy(function() { todos.length; // 4 }}
5 模板Templates(View层)
can.view,根据提供的Model数据渲染模板,并返回一个documentFragment 元素,EJS和 Mustache两种模板语言可以动态的bind到Observes.
Observes change—-> update your template in the DOM
5.1 加载模板
两种方式:从srcipt标签加载(id)和从url加载
Sricpt标签加载
定义
<script type="text/ejs" id="todoList"><% can.each(this,function(val, key){%> <li><%= val.attr('description')%></li><%});%></script>
通过ID加载
Todo.findAll({},function(todos){ $('#nav').html(can.view('todoList', todos)) });
通过url加载,模版内容是单独的文件
Todo.findAll({},function(todos){ $('#nav').html(can.view('todos/todos.ejs', todos)) });
5.2 Passing Deferreds(传递延迟对象)
can.view('todos.ejs',{ todos:Todo.findAll(). user:User.findOne({id:5})}).then(function(fragment){ document.getElementById('todos').appendChild(fragment);});
6 Mustache模版
Mustache是一个弱逻辑的模版语言,mustache提供了一些简单好用的标签来渲染绑定的Observes对象,我们可以使用自定义的Helpers(后面会讲到)来扩展它功能.
此处我们Mustache的官网地址http://mustache.github.io/;can只使用的Mustache的一些javascrpt简单的功能.
定义
<script id="template" type="text/mustache"> <h1>Welcome {{user}}!</h1> <p>You have {{messages}} messages.</p></script>
使用
var data = new can.Map({ user: 'Tina Fey', messages: 0});var template = can.view("#template", data)document.body.appendChild(template);
生成的Html
<h1>Welcome Tina Fey!</h1><p>You have 0 messages.</p>
6.1 加载/定义模版的方式
有两种方式Script Tags和URL两种方式
Script Tags方式:在html中嵌入模版脚本;使用
<script id="mytemplate" type="text/mustache"> My body lies over the {{.}}</script>
var template= can.view("#mytemplate",'water');can.$(document.body).append(template);
URL方式:把模版内容写在单独的一个文件中
var template = can.view('//lib/views/mytemplate.mustache', dataToPass);can.$(document.body).append(template);
6.2 模版标签
6.2.1 基本标签
{{key}} 输出html转义后的值{{{key}}} 同{{}},但是输出的是非转义的值{{! note }} 模版中的注释{{#key}}BLOCK{{/key}} 有两个功能:一是处理简单的逻辑判断,并根据结果渲染BLOCK.,二是遍历一个非空数组(后续详细介绍){{^key}}BLOCK{{/key}} 判断是key的值为false时,渲染BLOCK{{>key}} 嵌套模版;其中key是子模版的路径/Id
注:undefined, null, false, ”,0,和[]视为false,其他的视为ture
6.2.2 辅助标签
{{helper args…}}
调用Mustache辅助函数,将其返回值插入模板
{{#helper}}
{{#if key}}BLOCKA{{else}}BLOCKB{{/if}}
简单的逻辑判断 如果key是true则渲染BLOCKA 否则渲染BLOCKB
{{#each key}}
遍历一个数组/对象.当遍历数组时可以使用{{@index}}来获得索引;遍历一个数组时,可以使用{{@key}} 来获得对象的属性key
{{data name}}
在el上bind一个当前的contenxt,通过can.data(el,name)去获取
{{(el)->CODE}}
在el上执行内嵌回调代码,常用于对el上处理某操作 ;如{{(el)->el.hammer()}},对元素加上手持事件支持(hammer插件)
6.3 Context
上下文对象:(待续)
6.4 Helpers
Mustache可以注册一个方法用于在模版中调用,这样的方法就是Helpers,这个相当有用,因为Mustache是弱逻辑的模版,我们可以通过Helper来扩展一些逻辑处理.
模版
<scripttype="text/mustache"id="todosList">{{#todos}}<li>{{uppercase description}}</li>{{/todos}}</script>
脚本
var fragment= can.view('todosList',{todos: ['aa','bb']},{ uppercase:function(str){ return str.toUppercase(); }});
这就定义了一个转大写的helper方法
6.4.1 Global helpers
全局的Helpers 使用can.mustache.registerHelper或者Mustache.registerHelper去定义;全局Helpers对于任何Mustache模版都可以使用,这样相当于定义了公用的方法,任何地方都可以使用.
Mustache.registerHelper('money', function(price, option) { var temp = price; if ( typeof price == 'function') { temp = price(); } return can.mustache.safeString((temp/100).toFixed(1));});
示例中定义了一个对金额转化的helper,把传入的值除以100之后保留一位小数
6.4.2 Datahelpers
DataHelpe就是{{data name}}标签,在元素el上bind一个当前的context,通过can.data(el,name)去获取bind的context.示例:
<script type="text/mustache"id="nameDiv"><div {{data 'name'}} id ='test1'>{{myName}}</div></script>
$(body).append(can.view('nameDiv',{ myName:'JIM'}));var obj= can.data($('#test1'),'name'); //获取的 obj = { myName:'JIM'}
7 控制层 Controls
Controls 是Constructs的子类,它直接控制Model(由can.mode创建)并且结合View(Mustache由can.view创建)进行页面显示.
示例:
var Todos = can.Control({ default:{ age:23, name: 'sheldon1' }},{ init: function(el, options) { var self = this; Todo.findAll({}, function(todos) { self.element.html(can.view('todoList', todos)); }); }});
初始化一个Todos的实例如下:
var todosList = new Todos('#todos', {name:'sheldon',age:'27'});
第一个参数可以是选择器,元素,节点列表,这些在init方法中对应第一个参数中的el,此时的el已经是一个Dom元素对象.
第二个参数,options就是传入的json对象和上面提到的defaults里的值进行合并,可以用options.name来取得相对应的值。
7.1 Listening to events
Controls 会自动绑定那些看起来像事件的实例方法,如下面实例中的’li click’方法,这些方法传递两个参数,第一个是事件触发的元素,第二个是事件本身.
can.Control使用了事件托管,所以当添加或者移除元素时,不需要重新绑定事件处理。
varTodos= can.Control({ init:function(el, options){ var self=this; Todo.findAll({},function(todos){ self.element.html(can.view('todoList', todos)); }); }, 'li click':function(el, ev){ console.log('You clicked '+ el.text()); }, 'li .destroy click':function(el, ev){ var li= el.closest('li'), todo = li.data('todo'); todo.destroy(); }});
上面示例中当点击li .destroy元素时,调用了model的destory,从模型中删除了该对象,这样会同时把页面的对应的页面元素也删除掉。
7.2 Templating event handlers
如果在event handler中包含一个占位符,can.Control会在Control的option查找对应的占位符key的值,然后在window中查找.
var Todos = can.Control({defaults: { destroyEvent: 'click' }},{ init: function(el, options) { var self = this; Todo.findAll({}, function(todos) { self.element.html(can.view(this.options.view, todos)); }); }, 'li .destroy {destroyEvent}': function(el, ev) { var li = el.closest('li'), todo = li.data('todo'); todo.destroy(); }});new Todos('#todos', {destroyEvent; 'mouseenter'});
7.3 Rebinding events
Control可以通过调用on 方法Unbind和rebind所有的Control的event handlers,这个在Control开始监听一个指定的model或者改变监听的model时很常用。
varEditor= can.Control({ setDesc:function(){ this.element.val(this.options.todo.description); }, // change what Todo this Control points at todo:function(todo){ this.options.todo= todo; this.on(); this.setDesc(); }, // listen for changes in the Todo '{todo} updated':function(){ this.setDesc(); }, // when the input changes, update the Todo ' change':function(el, ev){ this.options.todo.attr('description', el.val()); this.options.todo.save(); }});var todo1=newTodo({id:7, description:'Take out the trash.'}), todo2 =newTodo({id:8, description:'Wash the dishes.'}), editor =newEditor('#editor');// start editing the first Todoeditor.todo(todo1);// switch to editing the second Todoeditor.todo(todo2);
7.4 Destroying Controls
Control调用destroy 方法会去除绑定的监听事件,同时移除它关联的元素,但是不回去移除页面上的页面元素。
var list=newTodos('#todos');$('#todos').length;// 1list.destroy();$('#todos').length;// 1
可是,当Control对应的页面元素被删除掉时,Control会去调用destroy 。
当一个应用在Body元素上添加Control和监听事件,我们可以通过调用$(document.body).empty().清除该Control的所有数据
8 组件 Components
Component 可以很容易的结合observables,templates,controls的功能特性。
can.Component.extend({ tag:"my-element", scope:{ visible:true, toggle:function(){ this.attr("visible",!this.attr("visible")) } }, template:"<div can-click='toggle'>"+ "{{#isVisible}}"+ "<content/>"+ "{{else}}"+ "I am hidden"+ "{{/isVisible}}"+ "</div>", helpers:{ isVisible:function(options){ returnthis.attr("visible")? options.fn(): options.inverse(); } }, events:{ "inserted":function(){ console.log("you add a my-element to the page") } }})
- tag -指定该Component的Html标签,用于在定义的标签中嵌入该component模版的内容.
- scope –can.Map结构,指定该Component的Model,用来渲染Component 的模版.
- template – Component的模版,渲染后的模版内容会嵌入到Component的THtml标签中.
- helpers – 作用于Component的mustache模版辅助方法.
- events – 类似Control的事件监听.
8.1 Tag
Tag:Component的标签,非Html解析的元素,当自定义的tab标签在模板中出现时,就会在这个标签元素上创建一个Component实例
can.Component.extend({tag:"todos-editor"});vartemplate= can.mustache("Here is my <todos-editor>todos-editor element</todos-editor>")var frag = template();frag.childNodes[1].nodeName//-> "todos-editor element"
注:tag必须小写,带有大写会出现找不到对应的tag问题
8.2 Template
可以是模版的字符串,也可使用can.view指向模版文件,或者使用can.Mustache指向一个已经定义好的Mustache模版
可以在模版中使用<content></context>
获取Component标签元素之间的内容
模版中的动态内容请参考第六章,这里要说明的是模版可以访问scope中的定义的属性/方法和helpers中定义的辅助方法.
8.3 Scope
Scope:一个can.map对象,作用在template上,在template中可以访问scope中的属性,
var template = can.mustache("<h1>Todo: {{mytodo.name}}</h1><todos-editor todo='mytodo'></todos-editor>");var mytodo = new can.Map({name: "Do the dishes"});can.Component.extend({ tag: "todos-editor", template: "{{#if todo}}<input type='text'can-value='todo.name'/>{{/if}}", scope: { placeholder:"@" }});var frag = template({ mytodo: mytodo})document.body.appendChild(frag)
注:can-value 是对于Scope中的属性和表单元素值双线绑定;即修改scope对于的属性表单元素的值也一起修改,修改表单元素的值Scope中对应的属性的值也同样会改变.使用@
符号获取Component标签元素中的属性值
这里着重说明下:
- 在Scope和helpers中定义的方法可以通过this.获取在Scope中方法/属性,在events中定义的方法要通过this.scope.
获取在Scope中方法/属性. - 访问Scope中的属性时,可以用 .属性名和 .attr(“属性名”) 两种方式访问,对于不会被监听的属性建议使用 .属性名访问. 对于会被用在Observes的,则建议使用.attr(“属性名”)中.
- 修改Scope属性:不被模版中访问的的属性建议使用直接赋值(this.aa = 123),而在模版中会被访问的属性使用.attr(“属性名”,属性值)方式修改属性值
8.3.1 Scope bindings
在scope中添加模板上的事件处理
can.Component.extend({ tag:"todos-editor", template:"<form can-click='toggle'>Editor: "+ "{{#if visible}}<input type='text'/>{{/if}}"+ "</form>", scope:{ visible:true, toggle:function(context, el, ev){ this.attr("visible",!this.attr("visible")) } }})
注: can-click=’toggle’表示给元素绑定click事件,事件触发调用的是scope中定义的方法.
8.3.2 Scope value functions
可以在template中访问Scope中的方法
can.Component.extend({ tag:"todos-editor", template:"<form can-click='toggle'>{{visibility}}: "+ "{{#if visible}}<input type='text'/>{{/if}}"+ "</form>", scope:{ visible:true, toggle:function(context, el, ev){ this.attr("visible",!this.attr("visible")) }, visibility:function(){ returnthis.attr("visible")? "visible":"invisible" } }})
8.3.3 Passing values to a component’s scope
通过在Component的元素上设置属性,可以向Component传递Scope上的数据
var template = can.mustache("<h1>Todo: {{mytodo.name}}</h1>"+ "<todos-editor todo='mytodo'></todos-editor>")var mytodo = new can.Map({name: "Do the dishes"})can.Component.extend({ tag: "todos-editor", template: "{{#if todo}}"+ "<input type='text' can-value='todo.name'/>"+ "{{/if}}", scope: {}})var frag = template({ mytodo: mytodo})document.body.appendChild(frag)
8.4 Helpers
见Mustache的helpers说明
8.5 Events
Events中可以定义对Route的监听,对Socpe中的对象监听(创建/修改/删除等),可以Dom元素上监听事件,也可以监听window上的事件
9 Routing
can.route 是CanJS路由的核心功能,也是一个特殊的Observe,当window.location.hash的值有变动时,can.route的属性值也会更新;同样,can.route的属性值有变动时,window.location.hash的值也会有更新。
可以给can.route附加一个传递URL属性的模板.Eg:
// Give can.route a template.can.route(':type/:id');// If you set a hash that looks like the route...window.location.hash='#!todos/5';// ... the route data changes accordingly.can.route.attr();// {type: 'todos', id: 5}// If the route data is changed...can.route.attr({type:'users', id:29});// ...the hash is changed using the template.window.location.hash;// '#!users/7'// You can also supply defaults for routes.can.route('',{type:'recipe'});// Then if you change the hash...window.location.hash='';// ...the route data reflects the defaults.can.route.attr();// {type: 'recipe'}
9.1 Listening to events
因为can.route也是一个Observe,所以也可以在它上面绑定监听事件
can.route.bind('id',function(ev, newVal, oldVal){ console.log('The hash\'s id changed.');});
你也可以在Control或者Component中监听 routingevents:
varRouting= can.Control({ 'route':function(){ // Matches every routing change, but gets passed no data. }, 'todos/:id route':function(data){ // Matches routes like #!todos/5, // and will get passed {id: 5} as data. }, ':type/:id route':function(data){ // Matches routes like #!recipes/5, // and will get passed {id: 5, type: 'recipes'} as data. }})
9.2 Making URLs and links
can.route.url: 根据当前的route,添加route属性并构造hash值 URL
can.route(':type/:id',{type:'todos'});can.route.url({id:7});// #!todos/7
can.route.link: 同can.route.url功能类似,但它是用来构造HTML中的A(链接元素)的href,同时也可为A元素添加一些属性。
var a= can.route.link( 'Todo 5', {id:7}, {className:'button'});a;// <a href="#!todos/7" class="button">Todo 5</a>
10 Utility Functions(见API)
- CanJS基础教程
- canjs基础教程之EJS
- Canjs基础教程之Controls
- canjs基础教程之Components
- canjs基础教程之Route
- Canjs基础教程之Mustach
- Canjs 基础教程之技巧篇
- 基础教程
- 基础教程
- JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
- JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
- JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
- JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
- JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
- JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
- JavaScript 基础教程
- JavaScript 基础教程
- XSL基础教程
- atoi 和itoa用法
- 详解CPU与Norflash电路连接图以及工作原理
- 安卓记住密码和自动登录
- 网络编程API-中 (高级I/O函数)
- 我的Java开发学习之旅------>Java NIO 报java.nio.charset.MalformedInputException: Input length = 1异常
- CanJS基础教程
- Android动画之Translate
- php wampserver的多站点配置
- STM8S003F使用I/O口模拟串口(一)发送数据
- 狂刷Android范例之4:用代码安装卸载app
- 25题~~字符串中找数字串
- Gridview求和,求平均数,非常简单实用
- 一个小型字符串工具类MString
- 缓存原理解析