当前位置: 首页 > 工具软件 > CanJS > 使用案例 >

Canjs 基础教程之技巧篇

江建明
2023-12-01

Component

Template

Use the tag to position the custom element’s source HTML.
使用标签获取自定义标签元素的源HTML内容.

can.Component.extend({
tag: "hello-world",
template: "<h1><content/></h1>"
});

Html Template

<hello-world>Hi There</hello-world>

Html

<hello-world><h1>Hi There</h1></hello-world>

Using html attributes like can-EVENT-METHOD, you can directly call a scope method from a template
使用html属性类似can-click=’back’方式,可以在template中访问定义在scope中的back方法.

Template中使用{{}}访问scope中的属性或方法.

Scope

If you want to set the string value of the attribute on scope, give scope a default value of “@”.
默认使用’@’符号获取自定义标签的属性值

    can.Component.extend({
      tag: "hello-world",
      template: "<h1>{{message}}</h1>",
      scope: {
        message: "@"
      }
    });
var template = can.mustache("<hello-world message='Howdy'/>");
template({})

<hello-world><h1>Howdy</h1></hello-world>

Scope也可以是一个function,但不常用.定义:function(attrs, parentScope, element)
attrs:custom element’s attributes(自定义标签元素的属性)
parentScope:(待理解)
element:自定义标签元素.

Events

A component’s events object is used as the prototype of a can.Control.
Component的Events对象被用作can.Control的原型属性.

The component’s scope is available within event handlers as this.scope.
在Events对象中使用this.scope.来访问Component的scope属性.

The events object can also listen to objects or properties on the component’s scope
Events对象同样可以监听Componet的scope对象的属性.
E.g.:监听scope的offset的属性变化,作相应的处理

can.Component.extend({
    tag: "my-paginate",
    template: "Page <span>1</span> <button class='next'>Next</button>",
    scope: {
            offset: 0,
            page: function() {}
    },
    events: {
            "{scope} offset": function() {
            this.element.find("span").text(this.scope.page())
            }
    }
});

在Components的Event中可以绑定inserted 和removed事件,用于监听Component的Tag在页面中的插入和删除

Tag

Tag请用小写定义,大写时有时会有问题

Control

Creating a control instance:new can.Control( element, options )

var todosControl = new Todos( '#todos', {} );

element: is the NodeList consisting of the element the control is created on
options :merged with the control’s static defaults property

Templated Event Handlers

Customize event handler behavior with “{NAME}” in the event handler name
自定义事件行为:在event定义中使用{Name}

    var Todos = can.Control.extend({
      init: function( element , options ) { ... },
      'li click': function( li ) { ... },
      'li .destroy {destroyEvent}': function( el, ev ) { ... }
    });
    // create Todos with this.options.destroyEvent
    new Todos( '#todos', { destroyEvent: 'mouseenter' } );

Values inside {NAME} are looked up on the control’s this.options first, and then the window.
{Name}中的值首先在control的this.options中查找,之后是window
E.g.:所以上面的例子,我们让他从window中查找:

    var Todos = can.Control.extend({
      init: function( element , options ) { ... },
      'li click': function( li ) { ... },
      'li .destroy {Events.destroy}': function( el, ev ) { ... }
    });
    Events = { destroy: 'click' };
    // Events.destroy is looked up on the window.
    new Todos( '#todos' );

If the value inside {NAME} is an object, Control will bind to that object to listen for events.
如果{Name}中的值是一个Object,Control将对一个该对象bind监听对应事件

    var Tooltip = can.Control.extend({
      '{window} click': function( el, ev ) {
        // hide only if we clicked outside the tooltip
        if ( !this.element.has( ev.target ) ) {
          this.element.remove();
        }
      }
    });

Defaults

Default options provided for when a new control is created without values set in options
Default Options 在新建一个Control对象时提供属性的默认值.

    Message = can.Control.extend({
      defaults: {
        message: "Hello World"
      }
    }, {
      init: function(){
        this.element.text( this.options.message );
      }
    });
    new Message( "#el1" ); //writes "Hello World"
    new Message( "#el12", { message: "hi" } ); //writes hi

Processors

can.Control already has processors for these events:
can.Control 可处理的事件如下:

change、click、contextmenu、dblclick、focusin、focusout、keydown、keyup、keypress、mousedown、mouseenter、mouseleave、mousemove、mouseout、mouseover、mouseup、reset、resize、scroll、select、submit

Route

Route events will be triggered whenever the route changes to the route part the control is listening to
当can.control监听的route部分的属性变动时将会触发route事件

var Router = can.Control({
    init : function(el, options) {
    },
    ":type route" : function(data) {
        // the route says anything but todo
    },
    "todo/:id route" : function(data) {
        // the route says todo/[id]
        // data.id is the id or default value
    },
    "route" : function(data){
        // the route is empty(route为空时触发)
    }
});
new Router(window);

Options

The this.options property is an Object that contains configuration data passed to a control when it is created (new can.Control(element, options))
This.options属性是一个在control创建是传递control的配置数据的Object
请查看Default中的示例代码!

Setup

Element

Map

Backup

can.Map.backup is a plugin that provides a dirty bit for properties on an Map, and lets you restore the original values of an Map’s properties after they are changed

var recipe = new can.Map({
      title: 'Pancake Mix',
      yields: '3 batches',
      ingredients: [{
        ingredient: 'flour',
        quantity: '6 cups'
      },{
        ingredient: 'baking soda',
        quantity: '1 1/2 teaspoons'
      },{
        ingredient: 'baking powder',
        quantity: '3 teaspoons'
      },{
        ingredient: 'salt',
        quantity: '1 tablespoon'
      },{
        ingredient: 'sugar',
        quantity: '2 tablespoons'
      }]
    });
    recipe.backup();
    recipe.attr('title', 'Flapjack Mix');
    recipe.title;     // 'Flapjack Mix'
    recipe.isDirty(); // true
    recipe.restore();
    recipe.title;     // 'Pancake Mix'

Validations

The can/map/validations plugin provides validations on maps

Contact = can.Map.extend({
    init : function(){
        // validates that birthday is in the future
        this.validate("birthday",function(birthday){
            if(birthday > new Date){
                return "your birthday needs to be in the past"
            }
        })
    }
},{});
var contact = new Contact({birthday: new Date(2012,0) })

Use errors ( [attrs…], newVal ) to read errors or to test if setting a value would create an error:
使用errors方法测试设置的值是否验证通过

Listen to changes in data

Use Model.bind(eventType, handler(event, model)) to listen to all events of type on a model and model.bind(eventType, handler(event)) to listen to events on a specific instance

使用Model.bind(eventType, handler(event, model))来监听某Model类型的事件,使用model.bind(eventType, handler(event))来监听摸model对象的的事件
一般有created、updated、destroyed三个事件

    // listen for when any todo is created
    Todo.bind('created', function( ev, todo ) {...})
    // listen for when a specific todo is created
    var todo = new Todo({name: 'do dishes'})
    todo.bind('created', function( ev ) {...})

Property Changes

    // listen for when the name property changes
    todo.bind('name', function(ev){  })

Listening with can.Control

    Todos = can.Control.extend({
      "{Todo} updated" : function(Todo, ev, todo) {...}
    })

Parse Model

can.Model.parseModel(data, xhr)
Expected data format: {id: 1, name : “dishes”},If your service returns data like
{ thingsToDo: {name: “dishes”, id: 5} }

假如使用findOne接受的数据是:{ thingsToDo: {name: “dishes”, id: 5} },而model对应期望的数据是{id: 1, name : “dishes”}时,可以使用如下方式处理

    Task = can.Model.extend({
     parseModel: function(data){
       return data.thingsToDo;
     }
    },{});

或者使用

    Task = can.Model.extend({
     parseModel: "thingsToDo"
    },{});

Fixture

(待续)

Mustache

Register Helpers
Eg:创建一个通用的Link

can.mustache.registerHelper('link', function(text, url) {
     text = can.esc(text);
     url  = can.esc(url);
     var result = '<a href="' + url + '">' + text + '</a>';
     return can.mustache.safeString(result);
});

Iteration

迭代一组字符串数组

    Template:
        {{#people}}
            {{.}} 
        {{/people}}
    Data:
        {
            people: ["Andy", "Austin", "Justin"]
        }
    Result:
        Andy Austin Justin

{{@index}}

The template:
    <ul>
      {{#each items}}
        <li> {{@index}} - {{.}} </li>
      {{/each}}
    </ul>
Rendered with:
    { items: ['Josh', 'Eli', 'David'] }
Renders:
    <ul>
      <li> 0 - Josh </li>
      <li> 1 - Eli </li>
      <li> 2 - David </li>
    </ul>

{{@key}}

The template:
    <ul>
      {{#each person}}
        <li> {{@key}}: {{.}} </li>
      {{/each}}
    </ul>
Rendered with:
{ person: {name: 'Josh', age: 27, likes: 'Mustache, JavaScript, High Fives'} }
Renders:
    <ul>
      <li> name: Josh </li>
      <li> age: 27 </li>
      <li> likes: Mustache, JavaScript, High Fives </li>
    </ul>

(待续)

 类似资料: