在Knockout视图模型中调用jQuery插件是一种有效的模式

Is calling jQuery plugins in a Knockout view model a valid pattern?

本文关键字:一种 有效 模式 模型 视图 Knockout 调用 插件 jQuery      更新时间:2023-09-26

我经常创建自定义绑定处理程序来更改DOM。但有时我会遇到这样的情况:我想把这种代码放在subscribe处理程序中。

MyModel =
{
    this.name = ko.observable();
    this.name.subscribe(function()
    {
        // is it correct to do these kind of calls inside a model?
        $.ajax(
        {
            url: "... url that creates customer on server ...",
            success: function()
            {
                $(".container_element").noty(
                {
                    text: "Customer created!"
                }); 
            }
        });
    });
}

Noty是一个弹出警报消息的jQuery插件,由于Noty实际上更改了DOM,建议的设计模式是什么?

如果您想在视图模型内部执行DOM操作,通常是一个危险信号(除了一些例外,最显著的是beforeRender&friends回调)。这是因为通常,使用MVVM风格的编程,您有一个依赖于视图模型的视图轻量级(具有声明性绑定),并且没有从视图模型到视图的依赖关系。这很好的两个主要原因:

  1. 您的虚拟机与视图没有紧密耦合,因此您可以根据同一视图模型轻松创建不同的视图
  2. 您的虚拟机更容易进行单元测试,因为测试单元不需要DOM

您已经提到了,您可能应该使用的东西:自定义绑定处理程序来自相关文档:

这就是如何控制可观察性如何与DOM元素交互,并为您提供了很大的灵活性,可以以易于重用的方式封装复杂的行为。

我找不到"Noty"示例自定义绑定,所以您必须创建自己的绑定(这通常并不难)。您可以从这个jQueryUI自定义绑定以及文档中获得一些灵感。

用你的例子把它放在代码中,事情看起来这个:

ko.bindingHandlers.noty = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // Set up any initial state, event handlers, etc. here
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var value = ko.utils.unwrapObservable(valueAccessor()),
            $el = $(element);
        if(!!value) { $($el).noty({text: value}); }
    }
};
// Mock $.ajax for this example
$.ajax = function(options) { options.success({}); }
MyModel = function()
{
    var self = this;
    this.name = ko.observable();
    this.myAlertMsg = ko.observable("");
    this.name.subscribe(function()
    {
        // is it correct to do these kind of calls inside a model?
        $.ajax(
        {
            url: "... url that creates customer on server ...",
            success: function()
            {
                self.myAlertMsg("Customer created!");
            }
        });
    });
}
ko.applyBindings(new MyModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-noty/2.3.4/packaged/jquery.noty.packaged.min.js"></script>
<div data-bind="noty: myAlertMsg"></div>
<input data-bind="value: name" /> (blur input to finish editing name)

请注意,我们需要var self = this习惯用法,以便能够在success回调中轻松引用视图模型。