是否可以暂停属性的初始 Knockout 评估,直到用户更改关联的可观察对象?
Is it possible to pause initial Knockout evaluation of an attribute, until a user changes the associated observable?
我正在开发一项网站功能,允许用户使用 knockout.js 对嵌入的 YouTube 视频进行实时更改(如大小和 URL)。该页面最初加载一个带有硬编码属性默认值和数据绑定的 iframe,但它尚未绑定。
<iframe data-bind="attr: {src: videoUrl() }, style: {width: width() + 'px', height: height() + 'px', }" style="width: 420px; height: 315px;" src="//www.youtube.com/embed/OvxlHa6yjqM" frameborder="0" allowfullscreen></iframe>
绑定会在一些用户交互后应用到 iframe - 比方说单击 'Show Options' 按钮。
$('some_button').click(function() { ko.applyBindings(viewModel) });
视图模型包含视频选项。
var viewModel = {
width: ko.observable(420),
height: ko.observable(315),
videoId: ko.observable('OvxlHa6yjqM')
}
iframe src 是一个计算的可观察对象。
viewModel.videoUrl = this.ko.computed( function () {
return 'http://www.youtube.com/embed/' + this.videoId();
}, viewModel );
一旦 ko.applyBindings()
被执行 knockout.js 评估所有绑定的可观察对象并在 HTML 中输出它们,即使它们与硬编码的相同。宽度和高度等属性会立即重新呈现,但控制 src
属性的 videoUrl
计算可观察对象会导致 iframe 重新呈现并闪烁一秒钟,即使它的 src
没有变化。如果用户输入新的 videoId
,iframe 将闪烁并重新呈现新视频,这是完全正常的。但是 有没有办法 prevent/pause 对 videoUrl
进行初始评估,直到它实际上被更改 为其他东西,例如通过输入一个新的 videoId
?
我试过 deferEvaluation
计算选项,但它对我不起作用(可能它的用途不同)。我尝试了一些条件绑定处理程序,但似乎无法找出正确的逻辑。
更新
Knockout.js 未加载到初始 iframe 加载的文档中。它加载在恰好是一个单独的 iframe 的选项容器中。这意味着 knockout 仅在用户调出选项(单击按钮)后加载并应用绑定到父文档中的 iframe。
视图模型因此分别应用于选项列表和 iframe 容器。
最简单的方法是在 DOM 加载时立即调用 applyBindings
,并且只有 show/hide 单击按钮时的选项。
首先,删除显式 src
属性并让 Knockout 在绑定时设置属性:
<iframe data-bind="attr: {src: videoUrl() }, style: {width: width() + 'px', height: height() + 'px', }" style="width: 420px; height: 315px;" frameborder="0" allowfullscreen></iframe>
然后将 applyBinding
调用移到点击处理程序之外:
$('bind').addEvent('click', function () {
this.hide();
$('options').show();
});
ko.applyBindings(viewModel);
我找不到一个神奇的解决方案,但毕竟我的问题很具体。我想出了一些解决这个问题的方法。
方法 1:在第一次更改后应用绑定
由于 ViewModel 分别应用于选项列表和 iframe,因此最简单的解决方案是首先仅将其应用于选项列表,然后仅在更改任何选项后才将其应用于 iframe。这样 iframe 不会在进入编辑模式时闪烁,但会在任何第一次更改时闪烁 - 即使这是对大小的更改。
方法 2:防止初始 iframe src 绑定
我在这里找到了一个很好的技巧:How to stop knockout.js bindings evaluating on child elements
在 iframe 的父元素上使用 stopBindings: true
(阅读上面的讨论)绑定,我能够正常应用绑定并且仅忽略 iframe 本身。现在我可以通过 viewModel.videoId.subscribe( function () {})
检测到视频源(视频 ID)的变化,并通过 ko.computedContext.isInitial()
检查这是否是初始变化。我可以将 stopBindings
设置为 false。缺点是,现在为了监视对 src 的更改,我需要使用 ko.cleanNode(element)
重新启动绑定,然后再次 ko.applyBindings
。但这有效,现在视频只有在更改 src 后才会闪烁。
方法 3:两个 ViewModel
我什至还没有开始探索这个解决方案,但它基本上涉及到 videoId
有一个单独的视图模型,它将在进行更改后应用 - 就像上面的解决方案一样。这将防止重新绑定,但我认为这是相当昂贵的。
我正在开发一项网站功能,允许用户使用 knockout.js 对嵌入的 YouTube 视频进行实时更改(如大小和 URL)。该页面最初加载一个带有硬编码属性默认值和数据绑定的 iframe,但它尚未绑定。
<iframe data-bind="attr: {src: videoUrl() }, style: {width: width() + 'px', height: height() + 'px', }" style="width: 420px; height: 315px;" src="//www.youtube.com/embed/OvxlHa6yjqM" frameborder="0" allowfullscreen></iframe>
绑定会在一些用户交互后应用到 iframe - 比方说单击 'Show Options' 按钮。
$('some_button').click(function() { ko.applyBindings(viewModel) });
视图模型包含视频选项。
var viewModel = {
width: ko.observable(420),
height: ko.observable(315),
videoId: ko.observable('OvxlHa6yjqM')
}
iframe src 是一个计算的可观察对象。
viewModel.videoUrl = this.ko.computed( function () {
return 'http://www.youtube.com/embed/' + this.videoId();
}, viewModel );
一旦 ko.applyBindings()
被执行 knockout.js 评估所有绑定的可观察对象并在 HTML 中输出它们,即使它们与硬编码的相同。宽度和高度等属性会立即重新呈现,但控制 src
属性的 videoUrl
计算可观察对象会导致 iframe 重新呈现并闪烁一秒钟,即使它的 src
没有变化。如果用户输入新的 videoId
,iframe 将闪烁并重新呈现新视频,这是完全正常的。但是 有没有办法 prevent/pause 对 videoUrl
进行初始评估,直到它实际上被更改 为其他东西,例如通过输入一个新的 videoId
?
我试过 deferEvaluation
计算选项,但它对我不起作用(可能它的用途不同)。我尝试了一些条件绑定处理程序,但似乎无法找出正确的逻辑。
更新
Knockout.js 未加载到初始 iframe 加载的文档中。它加载在恰好是一个单独的 iframe 的选项容器中。这意味着 knockout 仅在用户调出选项(单击按钮)后加载并应用绑定到父文档中的 iframe。
视图模型因此分别应用于选项列表和 iframe 容器。
最简单的方法是在 DOM 加载时立即调用 applyBindings
,并且只有 show/hide 单击按钮时的选项。
首先,删除显式 src
属性并让 Knockout 在绑定时设置属性:
<iframe data-bind="attr: {src: videoUrl() }, style: {width: width() + 'px', height: height() + 'px', }" style="width: 420px; height: 315px;" frameborder="0" allowfullscreen></iframe>
然后将 applyBinding
调用移到点击处理程序之外:
$('bind').addEvent('click', function () {
this.hide();
$('options').show();
});
ko.applyBindings(viewModel);
我找不到一个神奇的解决方案,但毕竟我的问题很具体。我想出了一些解决这个问题的方法。
方法 1:在第一次更改后应用绑定
由于 ViewModel 分别应用于选项列表和 iframe,因此最简单的解决方案是首先仅将其应用于选项列表,然后仅在更改任何选项后才将其应用于 iframe。这样 iframe 不会在进入编辑模式时闪烁,但会在任何第一次更改时闪烁 - 即使这是对大小的更改。
方法 2:防止初始 iframe src 绑定
我在这里找到了一个很好的技巧:How to stop knockout.js bindings evaluating on child elements
在 iframe 的父元素上使用 stopBindings: true
(阅读上面的讨论)绑定,我能够正常应用绑定并且仅忽略 iframe 本身。现在我可以通过 viewModel.videoId.subscribe( function () {})
检测到视频源(视频 ID)的变化,并通过 ko.computedContext.isInitial()
检查这是否是初始变化。我可以将 stopBindings
设置为 false。缺点是,现在为了监视对 src 的更改,我需要使用 ko.cleanNode(element)
重新启动绑定,然后再次 ko.applyBindings
。但这有效,现在视频只有在更改 src 后才会闪烁。
方法 3:两个 ViewModel
我什至还没有开始探索这个解决方案,但它基本上涉及到 videoId
有一个单独的视图模型,它将在进行更改后应用 - 就像上面的解决方案一样。这将防止重新绑定,但我认为这是相当昂贵的。