Не работает привязка нокаута для slick js

Мой рабочий код без привязки нокаута:

<div class="slick_demo_1">

                    <div>
                        <div class="ibox-content">
                            <h2>Slide 1</h2>
                        </div>
                    </div>
                    <div>
                        <div class="ibox-content">
                            <h2>Slide 2</h2>
                        </div>
                    </div>
                    <div>
                        <div class="ibox-content">
                            <h2>Slide 3</h2>
                        </div>
                    </div>
                </div>

И чтобы инициализировать пятно мой код JS:

$('.slick_demo_1').slick({
                dots: true
            });

Код выше работает нормально. Теперь код с привязкой нокаута:

<div class="slick_demo_1" data-bind="foreach:showSlider">

                    <div>
                        <div class="ibox-content">
                            <h2 data-bind="slider"></h2>
                        </div>
                    </div>
                </div>

И чтобы связать пятно с DOM мой код:

ko.bindingHandlers.slick = { 
            init: function (element, valueAccessor) {
                $(element).slick({
                    dots: true
                });
            }
        };

Но пользовательская привязка не работает. Что я делаю не так?

1 ответ

Решение

Код, который вы показываете, почти не похож на правильную реализацию пользовательского связующего.

Несколько подсказок:

  • вы должны использовать пользовательскую привязку в корневом элементе
  • пользовательская привязка должна заботиться о создании и, если возможно, удалении API карусели из элемента (используя slick's destroy или же unslick) если элемент утилизируется
  • пользовательское связующее должно иметь возможность обновлять элементы внутри карусели
  • было бы интересно использовать дополнительный slickOptions привязка для передачи дополнительных объектов в гладкую инициализацию

Базовая структура пользовательского связывания объясняется здесь. Смотрите шаблон кода:

ko.bindingHandlers.yourBindingName = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // This will be called when the binding is first applied to an element
    // Set up any initial state, event handlers, etc. here
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // This will be called once when the binding is first applied to an element,
    // and again whenever any observables/computeds that are accessed change
    // Update the DOM element based on the supplied values here.
}

};

Как объяснено, init отвечает за инициализацию карусели, а update отвечает за обновление содержимого карусели при изменении массива. R P Niemeyer дает подробное объяснение пользовательской привязки здесь: Другой взгляд на пользовательские привязки для KnockoutJS.

Если вы реализуете это правильно, ваш HTML-код должен выглядеть примерно так:

<div data-bind="slick: imagesArray, slickOptions: additionalOptions>
</div>

На init Ваша пользовательская привязка должна создавать элементы на основе imagesArray и вызвать гладкую инициализацию, используя additionalOptions если присутствует, и зарегистрируйте скользкое разрушение, когда элемент утилизируется с помощью ko. В обновлении вы должны изменить внутренние элементы и по возможности повторно применить слик. Вам также следует ознакомиться с API Slick.

Эта скрипка показывает частичную реализацию, но более полную, чем текущий фрагмент кода:

var imageUrls = [];
var i = 1;
for (i=1;i<=10;i++)
    imageUrls.push('http://lorempixel.com/400/200/animals/'+i);

ko.bindingHandlers.slick = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        // Clears the div
        $(element).empty();
        // Creates the inner divs with images
        var images = ko.unwrap(valueAccessor());
        if (images) {
         images.forEach(function(imgUrl) {
                $div = $('<div>');
                $image = $('<img>');
                $image.attr('src',imgUrl);
                $div.append($image);
                $(element).append($div)
            });
        }

        // try to recover slickOptions
        var options = allBindingsAccessor().slickOptions || {};

        // Initialize slick on the div, with provided options
        $(element).slick(options);

        //handle disposal, if KO removes the element
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $(element).slick('unslick');
        });
    },
    //update the control when the view model changes
    update: function(element, valueAccessor) {
        var images = ko.unwrap(valueAccessor());
        // Do something to update the content
    }
};


var vm = {
    images: ko.observableArray(imageUrls),
    options: {}
}

ko.applyBindings(vm, gallery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.slick/1.5.8/slick.min.js"></script>
<link href="https://cdn.jsdelivr.net/jquery.slick/1.5.8/slick.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/jquery.slick/1.5.8/slick-theme.css" rel="stylesheet">

<div id="gallery" 
     style="width:400px"
     data-bind="slick: images, slickOptions: {dots:true, initialSlide:4}">
</div>

Отсутствующая часть в реализации - обновление галереи, если изменяется imgUrls. Но он показывает основные приемы в подсказках.

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