有没有办法在ko.applyBindings()调用后应用组件绑定?
关键是,我使用requireJS来加载我的模块/组件异步。那么我如何知道所有绑定都已注册?
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();
答案 0 :(得分:5)
您可以使用几个部分来动态理解和加载组件。
您可以创建一个组件加载器,它可以从组件名称中理解需要的文件。
为了举例,假设任何以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-我们仍然需要处理custom elements,因为这些也会在注册时失效。该文档描述了可以覆盖的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警告here,因为它会影响动态了解自定义元素。
或者,您需要确保在该组件绑定到UI之前注册所有组件(不一定是在初始applyBindings时,但是一旦遇到需要绑定的组件)
答案 1 :(得分:0)
为了扩展RP Niemeyer的建议以确保在绑定被命中之前所有组件都已注册,我过去已成功完成此操作以加载我很少需要的组件。:
通过在根或控制器样式顶级模型的属性中使用组件并将其包装在with
绑定中,可以确保在注册组件之前未尝试组件绑定。在分配属性之前,KO不会评估with
内的任何内容。
这个例子比单词更容易解释!
所以这是你的代码,证明早期调用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);