从父级调用子组件中的函数的最佳方法?

时间:2016-11-17 10:26:29

标签: components ractivejs

当用户要求时,我有一个需要执行特定功能的ractive组件。即,不是在组件初始化时,而是在一段时间之后。

ractive docs mention events are used to communicate between components and their parents但仅限于从孩子到父母的事件的背景。在这种情况下,我们希望父级调用子级上的内容。

或者,有ractive.findComponent()但是这些例子似乎并没有太多用于从父母到孩子的传播。

我制作了以下使用findComponent()并使用的​​代码段(点击'运行代码段'然后'整页')。但是我不确定它是否是最佳的:

var coolWidget = Ractive.extend({
  data: {},
  template: `<span>Your favorite fruit is {{ fruit }}</span>`,
  data: function(){
    return {
      fruit: 'banana',
      doCoolThing: function(){
        var component = this;
        console.log('Going to change fruit...')
        setTimeout(function(){
          component.set('fruit', 'avocado')
        }, 3 * 1000)
      }
    }
  }
})

var ui = new Ractive({
  el: '.some-ui',
  data: { name: 'Mike'},
  components: {
    coolWidget
  },
  template: `
    <h1>Hello {{ name}}</h1>
    <button>Press me</button>
    <coolWidget />
  `,
  oncomplete: function(){
    var widget = this.findComponent('coolWidget')
    document.querySelector('button').addEventListener('click', function(){
      widget.get('doCoolThing')();
    })
  }
})
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<div class="some-ui">

</div>

从父级调用子组件中的函数的最佳方法是什么?

2 个答案:

答案 0 :(得分:2)

我试图通过评论来扩展@ rich-harris的答案,但显然这太长了。

如果你想让ractive管理你的接线多一点,你可以订阅并从根实例中激活事件:

在widget onrender中:this.coolThingListener = this.root.on('doCoolThing *.doCoolThing', function() { /* cool thing here */ })

在widget onunrender中:this.coolThingListener.cancel()

在主要实例模板中:<button on-click="doCoolThing">Press me</button>

当按下该按钮时,事件将冒泡到根实例,该实例具有任何doCoolThing事件的监听器(使用普通和加星标的版本确保任何嵌套组件可以除了根实例上的事件之外还触发它。唯一需要注意的是组件事件处理程序(this)中的coolThingListener将是根实例,因此您需要捕获组件引用或使用箭头函数。 / p>

如果你碰巧在根的生命周期中有多个组件实例存在,那么onunrender就会取消订阅。

这里整个事情在一起:

var coolWidget = Ractive.extend({
  data: {},
  template: `<span>Your favorite fruit is {{ fruit }}</span>`,
  onrender: function(){
    var component = this;
    // if 'doCoolThing' might fire from another component, add '*.doCoolThing' to listener to matching child component events too
    this.coolThingListener = this.root.on( 'doCoolThing', function(){ 
      component.doCoolThing(); 
    });
  },
  onunrender: function(){
    this.coolThingListener.cancel();
  },
  data: function(){
    return {
      fruit: 'banana'
    }
  },
  doCoolThing: function(){
    console.log('Going to change fruit...')
    setTimeout(function(){
      this.set('fruit', 'avocado')
    }, 3 * 1000)
  }
})

var ui = new Ractive({
  el: '.some-ui',
  data: { name: 'Mike'},
  components: {
    coolWidget
  },
  template: `
    <h1>Hello {{ name}}</h1>
    <button on-click="doCoolThing">Press me</button>
    <coolWidget />
  `
})

答案 1 :(得分:1)

如果doCoolThing是顶级选项......

var coolWidget = Ractive.extend({
  data: {},
  template: `<span>Your favorite fruit is {{ fruit }}</span>`,
  data: function(){
    return {
      fruit: 'banana'
    }
  },
  doCoolThing: function(){
    var component = this;
    console.log('Going to change fruit...')
    setTimeout(function(){
      component.set('fruit', 'avocado')
    }, 3 * 1000)
  }
})

...然后您可以像这样调用方法:

oncomplete: function(){
  var widget = this.findComponent('coolWidget')
  document.querySelector('button').addEventListener('click', function(){
    widget.doCoolThing();
  })
}

这不只是感觉更好,它实际上有一个实实在在的好处 - doCoolThing位于coolWidget原型上,因此无论多少个小部件都只创建一次被实例化。上下文绑定也没有内部错误。