4

有没有办法在 ko.applyBindings() 调用之后应用组件绑定?

关键是,我使用 requireJS 来异步加载我的模块/组件。那么我怎么知道所有的绑定都被注册了呢?

演示 JS 小提琴

ko.applyBindings();

ko.components.register('my-component',
    {
        viewModel: function() {
            this.name = ko.observable('My Name');
        },
        template: '<input type="text" data-bind="value: name"></input>'
    }
);

// Moving it here, it works:
// ko.applyBindings();
4

2 回答 2

6

您可以使用几个部分来动态理解和加载组件。

1-自定义组件加载器

您可以创建一个组件加载器,它可以从组件名称中理解需要哪些文件。

举个例子,假设任何以 开头的组件my-,我们希望按照components约定从目录中获取。

它可能看起来像:

//add a loader to the end of the list of loaders (one by default)
ko.components.loaders.push({
    getConfig: function(name, callback) {
        var widgetName;

        //see if this is one of our widgets
        if (name.indexOf("my-") > -1) {
            widgetName = name.substr(3).toLowerCase();

            //provide configuration for how to load the template/widget
            callback({
                require: "components/" + widgetName
            });
        } else {
            //tell KO that we don't know and it can move on to additional loaders
            callback(null);
        }
    },
    //use the default loaders functionality for loading
    loadComponent: ko.components.defaultLoader.loadComponent
});

如果默认加载器找不到组件(尚未注册),那么这个加载器就会启动。

2-我们仍然需要处理自定义元素,因为这些元素也需要注册。该文档描述了ko.components.getComponentNameForNode可以被覆盖以将元素标签动态转换为组件名称的方法。

在我们的例子中,这可能看起来像:

var existingGetComponentNameForNode = ko.components.getComponentNameForNode;
ko.components.getComponentNameForNode = function(node) {
    var tagNameLower = node.tagName && node.tagName.toLowerCase();

    //if we found one of our tags, then use it as the component name
    if (tagNameLower.indexOf("my-") > -1) {
        return tagNameLower;
    }

    // call the original
    return existingGetComponentNameForNode.apply(this, arguments);
};

这是一个将这些与 require.js 放在一起的小提琴:http: //jsfiddle.net/rniemeyer/tgm8wn7n/

另外,请注意此处的 IE6-8 警告,因为它会影响动态理解自定义元素。

或者,您需要确保在 UI 中绑定该组件之前注册所有组件(不一定在初始 applyBindings 时,而是在遇到需要绑定的组件时)。

于 2014-09-08T20:06:09.430 回答
0

为了扩展 RP Niemeyer 的建议,以确保在命中绑定之前注册所有组件,我过去曾成功完成此操作以加载我很少需要的组件。:

通过在根或控制器样式顶级模型的属性中使用组件并将其包装在绑定中,您可以确保在注册组件之前不尝试组件with绑定。with在分配属性之前,KO 不会评估 中的任何内容。

这比文字更容易用例子来解释!

所以这是你的代码,演示了applyBindings早期调用,然后使用超时来模拟稍后加载依赖于组件的代码:

标记:

<!-- ko with: Container -->
  <my-component>replaceme</my-component>
<!-- /ko -->

代码:

function Model()
{
        ko.components.register('my-component',
                {
                        viewModel: function() {
                                this.name = ko.observable('My Name');
                        },
                        template: '<input type="text" data-bind="value: name"></input>'
                }
        );
}

function RootModel()
{
        this.Container = ko.observable();

        this.load = function()
        {
                this.Container(new Model());
        };
}

var rootmodel = new RootModel();
ko.applyBindings(rootmodel);

setTimeout(function() { rootmodel.load(); }, 1000);

工作小提琴:http: //jsfiddle.net/whelkaholism/dhaox1ae/

于 2015-03-25T15:24:50.440 回答