每次viewmodel激活时,我都需要初始化第三方库 - videojs。但是,问题是库需要一个dom元素,当durandal激活回调时,它还没有附加。
//viewmodel
define (["jquery", "knockout", "videojs"], function ($, ko, videojs) {
var
activate = function (videoSource) { //route param
var videoTag = $('#video').get(0); //undefined
var playerInstance = new videojs.Player(videoTag); //error
playerInstance.src(videoSource); //loads video from route parameter
playerInstance.play(); //starts to play
};
return {
activate: activate
}
});
//view
<section id="page-quiz-answer" class="page">
<video id="video"></video>
</section>
答案 0 :(得分:1)
#activate回调中尚未提供DOM。您需要访问#attached或#compositionComplete回调中的DOM元素。您可以阅读here关于这些回调的签名及其预期用途。
//viewmodel
define (["jquery", "knockout", "videojs"], function ($, ko, videojs) {
var attached = function (view) { //route param
var $view = $(view);
var $videoTag = $view.find('#video'); //undefined
var playerInstance = new videojs.Player($videoTag); //error
playerInstance.src(videoSource); //loads video from route parameter
playerInstance.play(); //starts to play
};
return {
attached: attached
}
});
另一种方法
您还可以编写自定义Knockout绑定并封装访问DOM元素的逻辑。
我实际上会建议这种方法,因为我怀疑你将DOM引用传递给videojs.Player()
的点。这会在自定义绑定中进行封装。
<强> [编辑] 强>
使用自定义绑定的示例
在视图中考虑以下用法:
<div id='video' data-bind=player: {instance: playerInstance, source: videoSource}></div>
这样,您就可以将上面#attached函数中的所有逻辑移动到自定义绑定中。如果需要动态控制playerInstance,可以在viewmodel中创建一个具有observable属性的对象文字,如下所示:
var playerOptions = {
action: ko.observable('play'),
player: new videojs.Player(),
source: ko.observable(videoSource)
};
并将绑定更改为:
<div id='video' data-bind=player: {options: playerOptions}></div>
您的自定义绑定看起来像这样:
ko.bindingHandlers.player = {
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var options = ko.unwrap(valueAccessor),
$element = $(element);
var playerInstance = options.player;
playerInstance.source = options.source();
playerInstance.do(options.action());
}
};
我不确定您的播放器如何连接到DOM。我只能看到你在DOM元素中传递。但是在这个绑定中,你可以访问元素本身。