我有一个非常简单的用于 Knockout.js 的 Bootstrap Typeahead 绑定(jsFiddle),如下所示:
ko.bindingHandlers.typeahead = {
init: function (element, valueAccessor) {
var $e = $(element),
source = valueAccessor();
$e.typeahead({
source: source,
minLength: 0
});
},
};
它的用法很简单:
<input data-bind='typeahead: source, value: item,
valueUpdate: "afterkeydown"' />
绑定在jsFiddle中按预期工作。但是,当使用 RequireJS 加载时,它并不总是按预期工作。似乎存在竞争条件,因为 Knockout 和 jQuery 正在并行加载。
如果我查看change
绑定输入元素的事件处理程序,如果 jQuery 是处理程序,则绑定按预期工作。如果 Knockout 是change
事件的处理程序,则例如,如果您键入“alp”,并且 Typeahead 建议“Alpha”,并且您从 Typeahead 下拉列表中选择“Alpha”,则<input>
元素将显示所选文本(“Alpha” ),但绑定的 observable 将是“alp”。
在当前系统中,Typeahead 绑定不能直接修改给定的 observables,因此传递{ source: src, observable: item }
不会解决问题。这个 Typeahead 绑定的作用只是更新绑定的输入区域的内容。
我已经尝试从绑定中触发相关事件,例如“keydown”、“keypress”和“keyup”,但由于显而易见的原因,这不是一个非常有弹性的选项。
我怀疑这个问题与 RequireJS 的不确定性有关,Typeahead 插件的工作与否取决于首先加载的是 jQuery 还是 Knockout。特别是,似乎通过使用 RequireJS 使 jQuery 成为 Knockout 的依赖项(即首先加载 jQuery)解决了这个问题shim
:
requirejs.config({
shim: {
knockout: { deps: ['jquery'] },
}
});
这看起来很奇怪,我想更好地了解这里发生的事情以及这是否是问题的合理解决方案——即我实际上是在解决这里的潜在问题,还是这个问题会随着后续版本的 Knockout 或 jQuery 而出现。
我会很感激任何想法。
编辑
您可以通过按顺序内联加载脚本来简单地复制问题,例如:
<script src='knockout.js'></script>
<script src='jquery.js'></script>
这是一个展示该问题的jsFiddle。
按上述顺序插件将失败;否则它将按预期工作。
无论如何,RequireJS 配置是这样的:
requirejs.config({
baseUrl: "/script",
shim: {
knockout: { deps: ['jquery'] }, # remove this for race condition
}
});
main
has的简化版本require(['jquery', 'knockout', 'bindings'], ...)
,其中bindings
定义了 Knockout 处理程序。该bindings.js
文件有效地以define(['knockout', 'jquery'], ...)
.
在这种情况下,虽然问题不是 RequireJS,而是脚本的顺序。