按钮单击绑定并查看模型封装

时间:2014-10-24 13:05:55

标签: javascript ractivejs

我想使用Ractivejs实现简单的切换按钮功能。这是代码:

function MyViewModel(model) {
    var self = this;
    self.value = false;
    self.toggleValue = function () {
        self.value = !self.value; //this will probably not update view, but it is not the point here
    };
}

var viewModel = new MyViewModel(model);
var ractive = new Ractive({ el: 'mydiv', template: '#mytemplate', data: viewModel });

这是我的模板

<script id='mytemplate' type='text/ractive'>
    <p>Value: {{value}}</p>
    <button type="button">Toggle</button>
</script>

单击按钮时如何调用MyViewModel.toggleValue函数?现在我知道两个选择:

  1. 我可以将on-click='toggle("value")'添加到button元素。但是,让我们假设我的toggleValue函数可能稍微复杂一点,所以这个解决方案还不够。
  2. 我可以将on-click='toggleValue'添加到button元素。但后来我需要添加这段代码:

    ractive.on(&#39; toggleValue&#39;,function(){     viewModel.toggleValue(); });

  3. 这意味着:

    1. 我正在编写代码,必须了解此视图模型之外的视图模型。从封装角度来看,这很糟糕。
    2. 这也意味着toggleValue对于Ractive实例是全局的,而不是特定于视图模型,这意味着迟早会出现维护问题。
    3. 它没有比使用jQuery $("button").click(myFunction)更好。
    4. 那我该如何正确地做到这一点?我需要相当于KnockoutJs&#39; data-bind="click: toggleValue"

      编辑:有关工作代码,请查看此处:http://jsfiddle.net/xak5k8rd/

2 个答案:

答案 0 :(得分:4)

您可以通过向Ractive添加原型方法来创建该类型的语法:

Ractive.prototype.bind = function(context, method){

    // if using < 0.6.1 you may encounter bug {{this}} or {{.}} not returning model root
    //context = context || this.data

    context[method].call(context, this)
}

然后在模板中使用:

<button type="button" on-click="bind(this, 'toggleValue')">Toggle</button>
<ul>
{{#tab}}
    <li on-click="bind(this, 'click')">{{val}}</li>
{{/tab}}
</ul>

请参阅http://jsfiddle.net/obdk4k2o/2/

已编辑:为绑定功能添加了上下文。请注意,可以传递任何模板模型值,但this对于列表肯定很方便。

EDITED:在0.6.1中,方法调用可以访问this.event,这意味着密钥路径可用以及上下文(因此不需要传入)。

该方法变为:

Ractive.prototype.bind = function(method){
    var context = this.event.context,
        keypath = this.event.keypath
    context[method].call(context, this, keypath)
}

模板是:

<button type="button" on-click="bind('toggleValue')">Toggle</button>
<ul>
{{#tab}}
    <li on-click="bind('click')">{{val}}</li>
{{/tab}}
</ul>

在你的viewmodel中:

self.click=function(ractive, keypath){
    ractive.set(keypath + ".val", !self.val);
    alert('click');
}

请参阅http://jsfiddle.net/obdk4k2o/6/

答案 1 :(得分:0)

我认为第二种变体并没有错。 View有元素,当有人点击按钮时,view会传播某些事件。 View甚至不知道有人有该事件的监听器,并不关心某人是否真的有这种监听器。

IMO你只是通过命名事件来解决你的业务逻辑而感到困惑。但那是错的,IMO。 View应抛出一般事件,例如“点击了一个按钮,我不在乎是否有人想对它做点什么”。 IMO,通过该活动足以使层彼此分离。

像这样:

模板:

<script id='mytemplate' type='text/ractive'>
    <p>Value: {{value}}</p>
    <button type="button" on-tap="UserMakeSomeAction">Toggle</button>
</script>

JS:

ractive.on('UserMakeSomeAction', function () { viewModel.toggleValue(); });

P.S。此外,使用KnockoutJs的示例非常关注表示层与行为层的耦合。您的视图应该确切地知道控制器应该出现什么方法,知道它的名称,并调用它。 IMO,基于事件的传播要好得多。