Карусель Slick.js с пользовательской привязкой Knockout

Я хотел использовать потрясающую гладкую карусель ( http://kenwheeler.github.io/slick/) с Knockout. После рассмотрения некоторых других вопросов ( https://stackru.com/questions/26368176/slick-js-carousel-not-working-with-knockout-template-binding) кажется, что путь будет заключаться в использовании пользовательская привязка, но у меня возникают проблемы с ее правильной загрузкой - похоже, что гладкая карусель инициализируется до полной загрузки DOM, поэтому последний слайд не соединяется с первым слайдом. Я также посмотрел на пользовательскую привязку knockout js, вызываемую после рендеринга внутренних элементов dom, и пытаюсь использовать контексты дочерней привязки, чтобы пользовательская привязка заставляла дочерние элементы сначала связываться.

Вот 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 Можно ли обновить пятно, уничтожив и воссоздав карусель?

Любая помощь будет оценена! Я все еще изучаю пользовательские привязки, и если у кого-то был опыт работы с гладкой каруселью для работы с Knockout, было бы здорово услышать и о ней.

1 ответ

Решение

Отказ от ответственности: я никогда не использовал slick.js.

Вы правы, полагая, что карусель инициализируется до полной загрузки DOM.

Если вы выполняете поиск в stackru, вы найдете много опций о том, как вызывать функцию, когда все элементы закончили рендеринг - тот, который мне нравится больше всего, описан здесь: /questions/31569065/nokaut-posle-rendera-no-tolko-odin-raz/31569086#31569086.

Если у вас есть такой обратный вызов, вы можете использовать его для установки наблюдаемой в вашей основной viewModel true, как это:

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

Затем вы можете передать это наблюдаемое в качестве параметра вашей "гладкой" привязке, например так:

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

Всякий раз, когда наблюдаемая allElementsRendered() изменяется, вызывается функция 'update' в вашей пользовательской привязке - поэтому просто переместите туда логику инициализации, например так:

    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, должно поддерживать вашу карусель в актуальном состоянии.

Другие вопросы по тегам