在鼠标悬停时循环 AJAX 请求的图像,在鼠标离开时停止循环

Looping over AJAX requested images on mouseover, stopping the loop on mouseleave

我有一个模型网格,每个模型都包含 link、图像和名称。在 mouseenter 上,我希望每秒用循环中的 AJAX 加载图像列表替换悬停图像的 src 属性。在 mouseleave 上,原始图像应该恢复并且循环应该停止。

<div class="c-grid c-grid--models">
    <a href="#link-to-model" class="c-model" data-id="1">
        <figure class="c-model__wrap">
            <img src="http://placeholder.image" data-original="http://lazyloaded.image" class="c-model__image" />
            <figcaption class="c-model__name">Model 1</figcaption>
        </figure>
    </a>
    <a href="#link-to-model" class="c-model" data-id="2">
        <figure class="c-model__wrap">
            <img src="http://placeholder.image" data-original="http://lazyloaded.image" class="c-model__image" />
            <figcaption class="c-model__name">Model 2</figcaption>
        </figure>
    </a>
</div>

图像出现在视口中时会延迟加载。它们存储在数据原始标签中。下面是我开始工作的脚本。

    var _brakes = 1;
    var _timer1 = null;
    var _timer2 = null;
    var _data = null;
    $('.c-grid--models .c-model').hover(
        function() {
            _brakes = 0;
            _id     = $(this).attr('data-id');
            $image = $('img',$(this));
            var $this = $(this);
            _timer1 = setTimeout(function (){
                $this.request('onHover', {
                    data : {
                        id : _id
                    },
                    success: function(data) {
                        _data = $.parseJSON(data.result);
                        $.each(_data, function(i, new_image) {
                            _timer2 = setTimeout(function (){
                                if(_brakes == 0) {
                                    $image.attr('src', new_image);
                                } else {
                                    clearTimeout(_timer1);
                                    clearTimeout(_timer2);
                                    _data = null;
                                    _timer1 = null;
                                    _timer2 = null;
                                }
                            }, i * 1000);
                        });
                    }
                });
            }, 1000);
        }, function() {
            _brakes = 1;
            $image = $('img',$(this));
            $image.attr('src',$image.attr('data-original'));
            clearTimeout(_timer1);
            clearTimeout(_timer2);
            _data = null;
            _timer1 = null;
            _timer2 = null;
        }
    );

问题:

  1. 当到达最后一张图像时循环停止。我想一直循环直到触发 mouseleave 事件
  2. 在鼠标离开和鼠标(重新)进入时,图像旋转速度加快并且行为不稳定。似乎第一个循环没有正确停止。
  3. 来回悬停时,一个模型的图像与另一个模型的图像交叉。

注意:$(this).request('onHover'... 是 October CMS Ajax 框架的一部分。它执行一个 PHP 函数,该函数 returns 当前悬停的模型的所有图像的 JSON 数组。

谁能帮忙解决这个问题?可能是我使用的逻辑不对。任何投入将不胜感激。谢谢!

相关:

Stopping infinite loop on mouseleave or mouseout

好朋友帮我解决了问题

我们采用了不同的方法,将图像总数和当前图像存储在每个 html 元素的数据属性中。

我们现在不返回整个图像数组,而是逐个旋转图像。

新 HTML:

<div class="c-grid c-grid--models">
    <a href="#link-to-model" class="c-model" data-id="1" data-image-counter="5" data-current-image="0">
        <figure class="c-model__wrap">
            <img src="http://placeholder.image" data-original="http://lazyloaded.image" class="c-model__image" />
            <figcaption class="c-model__name">Model 1</figcaption>
        </figure>
    </a>
    <a href="#link-to-model" class="c-model" data-id="2" data-image-counter="5" data-current-image="0">
        <figure class="c-model__wrap">
            <img src="http://placeholder.image" data-original="http://lazyloaded.image" class="c-model__image" />
            <figcaption class="c-model__name">Model 2</figcaption>
        </figure>
    </a>
</div>

新 JavaScript:

$(function() {

    var hoveredItem = null;

    // Don't fire on touch devices
    if($('.c-grid--models').length && !Modernizr.touchevents) {

        $('.c-grid--models .c-model').hover(
            function() { // mouseenter

                $(this).data("mouse-hover", true);

                if(!$(this).data("is-busy") ) {
                    $(this).data("is-busy", true);
                    GetNextImage($(this));
                }
                // get next image with delay
            }, function() { // mouseleave
                // set original image and stop loop
                $(this).data("mouse-hover", false);
                var orignalimage = $("img",$(this)).data("original");
                $("img", $(this)).attr("src", orignalimage);
            }
        );
    }

    function GetNextImage(imageContainer) {
        hoveredItem = imageContainer;

        if (parseInt(imageContainer.data("image-counter")) <= 1) return;

        setTimeout( function() {

            if (imageContainer.data("mouse-hover") == true)
            {

                imageContainer.data("current-image", parseInt(imageContainer.data("current-image")) + 1);

                $(this).request("onHover", {
                    data: {
                        id: imageContainer.data("id"),
                        image_id: imageContainer.data("current-image")
                    }, success: function (data) {

                        // Reset
                        var total = parseInt(imageContainer.data("image-counter"))-1;
                        var current = parseInt(imageContainer.data("current-image"));
                        if (current >= total) imageContainer.data("current-image", 0);

                        // async callback finished. no longer busy
                        if (imageContainer.data("mouse-hover") == true) {
                            var _data = $.parseJSON(data.result);
                            $('img',imageContainer).attr('src', _data);

                            GetNextImage(imageContainer); //Loop
                        } else {
                            imageContainer.data("is-busy", false);
                        }
                    }
                });
            } else {
                imageContainer.data("is-busy", false);
            }
        }, 1000);
    }

    $(window).scroll(function() {
        if (hoveredItem != null) {
            hoveredItem.data("mouse-hover", false);

        }
    });
});

需要注意的重要一点是,滚动并不总是触发 onmouseleave。因此,在滚动时我们取消图像旋转,直到用户鼠标再次输入。

希望这对您有用。如果有不清楚的地方,请在下方评论,我会更新答案。