Knockout 自定义绑定有时不会初始化

Knockout Custom Binding does not Init sometimes

我创建了一个敲除自定义绑定,有助于启用 bootstrap 的模态功能。但是,有时当标记使用绑定时不会调用 init 方法。

// data-bind="bootstrapModal: {viewModel: {isOpen: ko.observable(false)}, backdrop: 'static'}"
ko.bindingHandlers.bootstrapModal = {
    init: function (elem, value) {
        debugger; // added for debugging

        var options = ko.utils.unwrapObservable(value()),
            viewModel = options.viewModel,
            backdrop = options.backdrop;

        /* added for debugging */
        console.log('Attaching boostrapModal binding to view model.');
        console.log(viewModel);

        debugger;
        /* end added for debugging */

        // do not allow backdrop = true for now; it doesn't sync with the view model
        if (backdrop === undefined || backdrop === true) {
            backdrop = 'static';
        }

        if (viewModel.isOpen()) {
            $(elem).modal({ show: true, backdrop: backdrop });
        }

        viewModel.isOpen.subscribe(function (newVal) {
            console.log('View model open toggle.');
            if (newVal) {
                $(elem).modal({ show: newVal, backdrop: backdrop });
            } else {
                $(elem).modal('hide');
            }
        });
    }
};

这与以下标记一起使用:

<div class="modal fade" tabindex="-1" role="dialog" data-bind="bootstrapModal: { viewModel: $data, backdrop: 'static' }, with: $data">
    <div class="modal-dialog" role="document">
    ... rest of modal markup

$data 是一个带有 isOpen 可观察布尔值的视图模型 属性(除其他外)。

在同一页面中,我们使用 require 引入如下脚本:

<script>
    requirejs(['knockout', 'NavViewModel'],
        function (ko, nav) {

            // investigating the binding handlers, bootstrapModal is available
            console.log(ko.bindingHandlers);
            debugger;

            ko.applyBindings(nav.NavViewModel.getInstance(), document.getElementById('navContainer'));
        });
</script>

我们正在使用 ASP.NET MVC 的捆绑器来创建一个包含 knockout 和我们所有自定义绑定的捆绑包,以便将它们一起下载。

BundleTable.Bundles.Add(new ScriptBundle("~/scripts/knockout.js")
            .Include("~/scripts/jquery-1.12.3.min.js")
            .Include("~/scripts/bootstrap.min.js")
            .Include("~/scripts/knockout-3.4.0.js")
            .Include("~/scripts/knockout.customBindings.js"));

这并不是真正的设置方式,但实际上是一样的。要求 'knockout' 将下载包 knockout.js,其中包含 jquery、bootstrap、knockout 和自定义绑定。

因此,在绑定发生之前,绑定处理程序在 ko.bindingHandlers 中可用。但是,自定义绑定中的断点(init 函数的第一行)并不总是命中。在 FF 中,我很少观察到错误。在Chrome,几乎每次都是。一遍又一遍地刷新页面最终会注意到两个浏览器中的工作状态和损坏状态。

即使脚本低于它所影响的标记,它也只是有时会实际应用绑定。将 applyBindings 调用移动到 DOM 就绪回调中解决了这个问题。

<script>
    requirejs(['jquery', 'knockout', 'NavViewModel'],
        function ($, ko, nav) {

            $(function() {
                ko.applyBindings(nav.NavViewModel.getInstance(), document.getElementById('navContainer'));
            });
        });
</script>