【问题标题】:Slick.js carousel with Knockout custom binding带有 Knockout 自定义绑定的 Slick.js 轮播
【发布时间】:2015-06-21 20:48:03
【问题描述】:

我想在 Knockout 中使用令人敬畏的光滑轮播 (http://kenwheeler.github.io/slick/)。在查看了其他一些问题 (https://stackoverflow.com/questions/26368176/slick-js-carousel-not-working-with-knockout-template-binding) 之后,似乎要使用自定义绑定,但我无法正确加载它 - 看起来光滑的轮播正在初始化之前DOM 已完全加载,因此它不会将最后一张幻灯片连接到第一张幻灯片。我还查看了knockout js custom binding called after internal dom elements rendered 并尝试使用子绑定上下文来让自定义绑定强制子元素首先绑定。

这里是html标记:

<div data-bind = "slick">
    <!-- ko foreach: results -->
      <div>
        <result-thumbnail params="result:$data"></result-thumbnail>
      </div>
    <!-- /ko -->
</div>

result-thumbnail 是一个单独的剔除组件,用于格式化我想在轮播中呈现的数据。在自定义绑定文件中:

ko.bindingHandlers.slick = {
init: function(element, valueAccessor, allBindingsAccessor, data, bindingContext) {
    var options = {
        infinite:true,
        slidesToShow: 3,
        slidesToScroll: 1,
    };

    var childBindingContext = bindingContext.createChildContext(
        bindingContext.$rawData, 
        null, 
        function(context) {
            ko.utils.extend(context, valueAccessor());
        });
    ko.applyBindingsToDescendants(childBindingContext, element);

    var local = ko.utils.unwrapObservable(valueAccessor());
    ko.utils.extend(options, local);
    $(element).slick(options);
    return { controlsDescendantBindings: true };
},
update: function(element, valueAccessor, allBindingsAccessor, data, context) {
  }
};

我正在考虑的一些事情: - 我应该将光滑的初始化移动到更新功能吗? - 我写的自定义绑定是否需要绑定到不同的元素? - 如果我要更改 results observable 的值,我是否需要通过销毁然后重新创建轮播来更新 slick?

任何帮助将不胜感激!我仍在学习自定义绑定,如果有人有过让光滑的轮播与 Knockout 一起工作的经验,那也很高兴。

【问题讨论】:

    标签: knockout.js ko-custom-binding


    【解决方案1】:

    免责声明:我从未使用过 slick.js。

    您认为轮播在 DOM 完全加载之前初始化是正确的。

    如果您在 stackoverflow 上进行搜索,您会发现很多关于如何在所有元素都完成渲染后调用函数的选项 - 我最喜欢的一个在此处描述:https://stackoverflow.com/a/19941134/3620458

    一旦你有了这样的回调,你就可以用它在你的主 viewModel 中设置一个 observable 为true,像这样:

    var allElementsRendered = ko.observable(false);
    var yourAfterRenderFunction = function () {
        allElementsRendered(true);
    }
    

    然后您可以将该 observable 作为参数传递给您的 'slick' 绑定,如下所示:

    <div data-bind = "slick: allElementsRendered">
    

    每当 allElementsRendered() observable 发生变化时,都会调用自定义绑定中的“更新”函数 - 所以只需将初始化逻辑移到那里,如下所示:

        update: function(element, valueAccessor, allBindingsAccessor, data, context) {
            var shouldInit = ko.unwrap(valueAccessor());
    
            if (shouldInit) {
                var options = {
                    infinite:true,
                    slidesToShow: 3,
                    slidesToScroll: 1,
                };
    
                $(element).slick(options);
            } else {
                $(element).slick("unslick");
            }
        }
    

    处理更新结果 observableArray 可能需要一些额外的工作 - 您可以订阅它并在其更改时将 allElementsRendered() 设置为 false,如下所示:

    var resultsSubscription = results.subscribe(function(newValue){
        allElementsRendered(false);
    })
    

    结合上面提到的 afterRenderFunction 应该可以让您的轮播保持更新。

    【讨论】:

    • 感谢您的帮助!我昨天尝试了这个,我能够在渲染所有子 div 元素后初始化光滑的轮播,但我认为我必须更多地研究光滑轮播的渲染方式,以便我可以继续更新轮播有了新的结果。一旦我得到最终的解决方案,我会在这里添加它。
    • 你找到最终解决方案了吗? :) 我对你是怎么做到的很感兴趣 :)
    • 上述答案中缺少的部分是何时将 allElementsRendered 设置为 true。为了仅在渲染所有子元素后将其设置为 true。添加在渲染每个子元素后调用的 afterRender 处理程序。参考此stackoverflow.com/a/14254390 并在呈现最后一个子元素时将 allElementsRendered 设置为 true。我试过会发布更清洁的样本。
    猜你喜欢
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-14
    相关资源
    最近更新 更多