实例组件

定义组件就是定义类,你可以手动调用new实例化该类。Intact实例章节中,我们提到了怎么实例化,并且渲染它。但它是作为根组件挂载到页面中的。其实我们也可以将实例当做普通数据,就像插值一样在模板中直接渲染。这就是Intact支持的实例组件。

实例组件提供了直接操作组件的能力,你可以设置和获取组件渲染的各个细节。

  1. var Component = Intact.extend({
  2. template: '<div>{self.get("data")}</div>'
  3. });
  4. Intact.extend({
  5. template: '<div>{self.get("view")}</div>',
  6. defaults: function() {
  7. return {
  8. // 直接实例化组件
  9. view: new Component({data: 'hello'})
  10. }
  11. }
  12. });

另一个常见的例子是SPA应用中,使用前端路由切换页面。我们可能需要等到异步组件数据加载完毕才开始切换页面,并且在数据加载的过程中,需要展示loading动画。我们可以如下这么做:

  1. var PageA = Intact.extend({
  2. template: '<div>PageA, router: {self.get("router")}</div>',
  3. _init: function() {
  4. return new Promise(function(resolve, reject) {
  5. setTimeout(resolve, 1000);
  6. });
  7. }
  8. });
  1. var PageB = Intact.extend({
  2. template: '<div>PageB, router: {self.get("router")}</div>',
  3. _init: function() {
  4. return new Promise(function(resolve, reject) {
  5. setTimeout(resolve, 1000);
  6. });
  7. }
  8. });

上述两个组件都模拟1s来加载数据,下面我们定义一个根组件来管理它们。

  1. <div>
  2. {self.get('view')}
  3. <div v-if={self.get('loading')}>Loading...</div>
  4. <button ev-click={self.toggle}>加载组件</button>
  5. </div>
// 模拟hash路由
var router = {
    '/a': PageA,
    '/b': PageB
};
var hash;
Intact.extend({
    template: template,

    toggle: function() {
        this.set('loading', true);
        hash = hash === '/a' ? '/b' : '/a';
        var Page = router[hash];
        // 实例化组件
        var page = new Page({router: hash});
        this.set('view', page);
        // 判断实例是否数据加载完成
        if (page.inited) {
            // 如果加载完成
            this.set('loading', false);
        } else {
            // 否则等实例加载完成后才挂载
            page.one('$inited', function() {
                this.set('loading', false);
            }.bind(this));
        }
    }
});

实例组件让你可以控制组件的实例化,这在前端路由中很实用。例如:/user/1/user/2两个页面都对应同一个组件,只是参数不同,这样你可以为每个页面实例化一个组件传入不同的用户ID。如果不采用实例组件,你可能需要为每个组件指定一个唯一的key,否则因为是同一个组件,两个页面不是替换关系,而是更新,这样上一个页面的数据就会带到下一页了。当然你也可以监听用户ID的变化,只是这样处理起来不如实例组件来的简单。