在durandal生命周期回调中初始化第三方库

时间:2014-03-21 20:42:42

标签: javascript durandal

每次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>

1 个答案:

答案 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元素中传递。但是在这个绑定中,你可以访问元素本身。