Knockout sliding images issue with custom binding

2019-06-14 05:17发布

I want to implement scrolling images on my product listing page when a user hovers on the product tile. Initially the first image will be displayed and when hovered the slide show shall begin. Each product tile will have different number of images for slide show.

Issue: When hovered on an image with five images in an array, the slide show starts and second image is shown.But the instead of third image again first image is getting displayed. Below is the sequence: Number denotes the index of images 1,2 1,2,3 1,2,3,4 1,2,3,4,5 Expected: 1,2,3,4,5

Also Observed that the mouse hover event gets unregistered.

Below is the code:

<div class="customized-slider-wrapper" data-bind="PLPTileSizeOnHover: $data">
    <div class="customized-slider" data-bind="foreach: fullImageURLs">
    <div class="individual-tile">
        <img data-bind="attr: { src: $index() === 0? $data : '../file/general/show_loader_showcase.gif' }" class="product-images" />
    </div>
    </div>
</div>

KO code

  ko.bindingHandlers.PLPTileSizeOnHover = {
      init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var data = ko.unwrap(valueAccessor());
       // Intiallizing variables for product image animation
        var _index = 0;
        var imgArray = data.fullImageURLs();
        var toBeScrolledBy = 0;
        var scroller = $(element).find('.customized-slider').eq(0);
        var StopAnimation;
        element.onmouseover = function () {


          //Start Animation
          StopAnimation = setInterval(function () {
            var totalSlides = $(element).find('.customized-slider').eq(0).children();
            var slideWidth = totalSlides[0] && totalSlides[0].clientWidth;
            _index++;
            $($(element).find('.product-images')[_index]).attr('src', imgArray[_index]);
            if (_index >= imgArray.length) {
              _index = 0;
            }
            toBeScrolledBy = slideWidth * _index;
            $(scroller).css({
              'transform': 'translateX(-' + toBeScrolledBy + 'px)'
            });
          }, 1500);
        }

        element.onmouseout = function () {

          //End of animation and reseting the index and div postion
          clearInterval(StopAnimation); 
          _index = 0;
          $(scroller).css({
            'transform': 'translateX(0)'
          });
        }
      }
    }

Requirement is to load images one by one when hovered. cannot load all images first.

Code works on chrome when dev tool is kept on.

fiddle https://jsfiddle.net/harpreetsjs/cvzrnaLy/

1条回答
戒情不戒烟
2楼-- · 2019-06-14 05:39

The problem is the mouseover and mouseout events. They are fired also for the element's children and bubble up. Therefore you "randomly" get these events as the children move around. Instead you want to use mouseenter and mouseleave.

I've incorporated this change as well as some general cleanup:

ko.bindingHandlers.PLPTileSizeOnHover = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var data = ko.unwrap(valueAccessor());
        console.log(data);
        // Intiallizing variables for product image animation
        var _index = 0;
        var imgArray = data;
        var toBeScrolledBy = 0;
        var scroller = $(element).find('.customized-slider').eq(0);
        var StopAnimation;
        element.onmouseenter = function() {
            //Start Animation
            console.log("start");
            StopAnimation = setInterval(function() {
                console.log("Started " + _index);
                var totalSlides = scroller.children();
                console.log("totalSlides " + totalSlides.length);
                var slideWidth = totalSlides[0] && totalSlides[0].clientWidth;
                console.log('slideWidth', slideWidth);
                _index++;
                scroller.find('.product-images').eq(_index).attr('src', imgArray[_index]);
                if (_index >= imgArray.length) {
                    _index = 0;
                }
                toBeScrolledBy = slideWidth * _index;
                scroller.css({
                    'transform': 'translateX(-' + toBeScrolledBy + 'px)'
                });

            }, 1500);
        }

        element.onmouseleave = function() {
            //End of animation and reseting the index and div postion
            console.log("clear");
            clearInterval(StopAnimation);
            _index = 0;
            scroller.css({
                'transform': 'translateX(0)'
            });
        }
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        console.log("Update cakked");
    }
}


var fullImageURLs = ko.observableArray([
    'https://product-images.barneys.com/is/image/Barneys/505670716_1_ShoeSide?$oc_grid_fixed$',
    'https://product-images.barneys.com/is/image/Barneys/505670733_1_ShoeSide?$oc_grid_fixed$',
    'https://product-images.barneys.com/is/image/Barneys/505670750_1_ShoeSide?$oc_grid_fixed$   '
]);
console.log(fullImageURLs());
ko.applyBindings(fullImageURLs);
.customized-slider-wrapper {
    height: 370px;
    position: relative;
    overflow: hidden;
    width: 100%;
    width: 231px;
}

.customized-slider {
    position: absolute;
    left: 0;
    width: 1800px;
    height: 100%;
    transition: transform .5s ease 0s;
    display: block;
}

.individual-tile {
    float: left;
}

.customized-slider-wrapper .customized-slider>div img {
    height: 252px;
    float: none;
    display: block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    margin: 0 auto;
    vertical-align: middle;
    border: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<a class="search-products-images">
    <div class="customized-slider-wrapper" data-bind="PLPTileSizeOnHover: $data">
        <div class="customized-slider" data-bind="foreach: $data">
            <div class="individual-tile">
                <img data-bind="attr: { src: $index() === 0? $data : 'http://placehold.it/106&text=1' }" class="product-images" />
            </div>
        </div>
    </div>
</a>

查看更多
登录 后发表回答