Web page carousel exercise (case)

The carousel image, also known as the focus image , is a relatively common web page special effect in web pages.

Functional Requirements:

  1. When the mouse passes over the carousel, the left and right buttons are displayed, and the left and right buttons are hidden;
  2. Click the right button once, the picture will play one picture to the left, and so on, the left button is the same;
  3. While the picture is playing, the small circle module below changes accordingly;
  4. Click the small circle to play the corresponding picture;
  5. The carousel will also automatically play the picture if the mouse does not pass over the carousel;
  6. When the mouse is placed on the carousel, the autoplay will stop.

case analysis:

① Because there are many JS files, first create a separate JS folder, then create a new JS file and import it into the page.

② At this point, the load event needs to be added.

③The mouse passes over the carousel map module, the left and right buttons are displayed, and the left and right buttons are hidden when the mouse is left.

④ Show and hide display.

// 1.获取元素
var prev = document.querySelector('.prev');
var next = document.querySelector('.next');
var focus = document.querySelector('.focus');
// 2. 鼠标经过focus 就显示隐藏左右按钮
focus.addEventListener('mouseenter', function () {
        prev.style.display = 'block';
        next.style.display = 'block';
    })
focus.addEventListener('mouseleave', function () {
        prev.style.display = 'none';
        next.style.display = 'none';
    })

Considering that the number of small circles corresponds to changes in the number of pictures, it will be troublesome to manually change the code every time an image is added. Let’s analyze how to dynamically generate small circles.

Dynamically generate small circles:

① Core idea: The number of small circles should be consistent with the number of pictures;

② So first get the number of pictures in ul (the picture is put in li , so it is the number of li );

③ Use the loop to dynamically generate a small circle (this small circle should be put into the ol );

④ Create node createElement('li') ;

⑤ Insert node ol.appendChild(li) ;

⑥ The first small circle needs to add the current class.

Click on the small circle and find that the small circle you click on will change color, and the other small circles will not change color. This is associated with the idea of ​​​​exclusivity, so,

Exclusive Thoughts from Small Circles:

① Click the current small circle to add the current class;

② For the rest of the small circles, remove the current class;

③ Note: We can directly bind this click event while generating the small circle just now.   

// 3.动态生成小圆圈  有几张图片,就生成几张小圆圈
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('.circle');
    for (var i = 0; i < ul.children.length; i++) {
        // 创建一个小 li
        var li = document.createElement('li');
        // 记录当前小圆圈的索引号 通过自定义属性来做
        li.setAttribute('index', i);
        // 把小 li 插入到 ol 里面
        ol.appendChild(li);
        // 4. 小圆圈的排他思想 我们可以直接在生成小圆圈的同时直接绑定点击事件
        li.addEventListener('click', function () {
            // 干掉所有人 把所有的小 li 清除 current 类名
            for (var i = 0; i < ol.children.length; i++) {
                ol.children[i].className = '';
            }
            // 留下我自己 当前的小 li 设置 current 类名
            this.className = 'current';

Next, click the small circle to achieve the effect of scrolling the picture. At this time, the animate animation function is used:

① Introduce  the js file of the animate animation function (note that because index.js depends on animate.js , animate.js should be written on index.js )

<!-- 引入JS文件 -->
    <!-- 这个animate.js必须写在 index.js的上面引入 -->
    <script src="JS/animate.js"></script>
    <script src="JS/index.js"></script>

② The premise of using the animation function is that the element must be positioned;

③ Note that  ul  moves instead of  li  ;

④ The core algorithm of scrolling pictures: click on a small circle, let the picture scroll the index number of the small circle multiplied by the width of the picture as the ul  movement distance;

⑤ At this time, we need to know the index number of the small circle. We can set a custom attribute for the small circle when generating it, and get this custom attribute when clicking.

// 留下我自己 当前的小 li 设置 current 类名
            this.className = 'current';
// 5. 点击小圆圈,移动图片,当然移动的是 ul
// ul 的移动距离 = 小圆圈的索引号 乘以 图片的宽度 注意是负值
// 当我们点击了某个小 li 就拿到当前小 li 的索引号
 var index = this.getAttribute('index');
 animate(ul, -index * focusWidth);

In the same way, the next step is to achieve the effect of scrolling the picture by clicking the left and right buttons. Click the right button once to scroll the picture to the left. The method is as follows:

① Declare a variable num , click once, increment by 1, and multiply this variable by the image width, which is the scrolling distance of ul  ;

② The principle of seamless scrolling of pictures;

③ Make  a copy of  the first  li  of ul and put it at the end of ul ;

④ When the picture scrolls to the last cloned picture, let  ul jump to the far left quickly and without animation: left is 0;

⑤ At the same time  , num  is assigned a value of 0, and the picture can be scrolled from the beginning.

However, it would be troublesome to manually copy pictures (change the structure) in HTML and CSS. Imagine that the effect of automatically cloning the last picture can be realized by modifying JS, so:

① Clone  ul first  li cloneNode ()  parentheses, add true to deep clone and copy the child nodes inside, add  false  to shallow clone, do not copy nodes;

② Add  appendChild to the end of ul ;

The next step is to realize that the small circle changes with the button:

Click the button, the small circle follows the change

① The easiest way is to declare a variable circle , which increments by 1 each time you click. Note that the left button also needs this variable, so you must declare a global variable;

② But there are 7 pictures (the last one is a copy), and there are only 6 small circles, one less, and a judgment condition must be added;

③ If circle == 6, it will be restored to 0 again.

Considering that the number of pictures changes dynamically (if you want to increase or decrease pictures), it is enough to judge  circle == ol.children.length (that is , to judge whether it is equal to the number of small circles)

 // 把 ol 里面的第一个小 li 设置类名为 current
    ol.children[0].className = 'current';
 // 6. 克隆第一张图片(li)放到最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
 // 7. 点击右侧按钮,图片滚动一张
    var num = 0; // num 是全局变量
 // 声明一个变量 circle 控制小圆圈的播放
    var circle = 0;
// 右侧按钮
    next.addEventListener('click', function () {
        // 如果走到了最后复制的一张图片,此时 ul 要快速复原 left 改为 0
        if (num == ul.children.length - 1) {
            ul.style.left = 0;
            num = 0;
        }
        num++;
        animate(ul, -num * focusWidth);
        // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放
        circle++;
        // 如果circle == 6 说明走到最后克隆的这张图片 我们就复原为0
        if (circle == ol.children.length) {
            circle = 0;
        }
        // 先清除其余小圆圈的 current 类名
        for (var i = 0; i < ol.children.length; i++) {
            ol.children[i].className = '';
        }
        // 留下当前的小圆圈的current类名
        ol.children[circle].className = 'current';
    })

By doing this, the button picture and the small circle are changed synchronously, but there is a small bug, that is, after clicking the small circle to a certain picture, clicking the button should jump to the next picture, but the result is that it will jump Going to the previous picture of this picture, this problem is because the animation of clicking the button is   controlled  by the num variable, and the picture played by the small circle is  controlled by the index number of the index  in the li click event, so the index number must be equal to num . However, in order to achieve a synchronous change among the small circle, button, and picture, the values ​​of the three must be equal, that is, after obtaining the index number of the small circle, directly make the three equal (here num and circle   are  global variables   , The li  click event is declared outside the click event)

var index = this.getAttribute('index');
// 当我们点击了某个小 li 就要把这个 li 的索引号给 num 和 circle
   num = circle = index;

left button

Click the button on the left, since  num  is assigned a value of 0, set the precondition and jump to the last picture copied from the first picture, whose index number is  ul.children.length - 1  , then  the distance moved by ul can be calculated come out:

prev.addEventListener('click', function () {
        if (num == 0) {
            num = ul.children.length - 1;
            ul.style.left = -num * focusWidth + 'px';
        }
        num--;
        animate(ul, -num * focusWidth);
    })

In the same way, because circle is initially assigned  a value  of 0, then  circle--  is a negative value. Using this judgment condition, when  circle < 0  , it is necessary to change the small circle to the last small circle, that is,  ol.children.length - 1  , and the style change of the small circle, that is, the class name change, because it is the same as the code of the button on the right, it can be encapsulated in a function to optimize the code

circle--;
        // 如果circle < 0 说明第一张图片 则小圆圈要改为第6个小圆圈
        if (circle < 0) {
            circle = ol.children.length - 1;
        }
        // 调用函数
        circleChange();
// 优化代码,封装函数
    function circleChange() {
        for (var i = 0; i < ol.children.length; i++) {
            ol.children[i].className = '';
        }
        // 留下当前的小圆圈的current类名
        ol.children[circle].className = 'current';
    }

So far, the basic effect has been realized.

The next step is to realize the effect of automatic animation playback :

Autoplay can be associated with timers, then

① Add a timer;

② Automatically play the carousel, which is actually similar to clicking the button on the right;

③ At this point we manually call the right button click event next.click() ;

④ Stop the timer when the mouse passes the focus;

⑤ Start the timer when the mouse leaves the focus.

Therefore, the function of the timer can be written like this

// 10. 自动播放轮播图
    var timer = setInterval(function () {
        // 手动调用右侧按钮点击事件
        next.click();
    }, 2000)

After the mouse stops the timer (clear the timer) and leaves (pull the code of the timer directly, no need to define), the effect needs to go back to the previously written code to modify, add a few lines of code, as follows:

// 2. 鼠标经过focus 就显示隐藏左右按钮以及停止和开启定时器
    focus.addEventListener('mouseenter', function () {
        prev.style.display = 'block';
        next.style.display = 'block';
        clearInterval(timer);
        timer = null;// 清除定时器变量
    })
    focus.addEventListener('mouseleave', function () {
        prev.style.display = 'none';
        next.style.display = 'none';
        timer = setInterval(function () {
            // 手动调用右侧按钮点击事件
            next.click();
        }, 2000)
    })

Finally, the carousel map also involves a problem, that is, clicking the button to play the picture will be too fast, thus introducing a concept- throttle valve

The throttle valve is to prevent the carousel button from being played too fast due to continuous clicks.

Throttle valve purpose: When the content of the previous function animation is executed, the next function animation is executed, so that the event cannot be triggered continuously.

The core implementation idea: use the callback function, add a variable to control, lock the function and unlock the function.

start setting a variable

var flag = true;

If (flag)

{flag = false; do something} closes the tap

Use the callback function to complete the animation, flag = true to open the faucet

Therefore, in the click event, the code is executed first, but because the flag = false, the code will not be executed below, and the  flag = true can be re-opened through the callback function in the animate animation function

if (flag) {
            flag = false;//关闭节流阀
            if (num == ul.children.length - 1) {
                ul.style.left = 0 + 'px';
                num = 0;
            }
            num++;
            animate(ul, -num * focusWidth, function () {
                flag = true;//打开节流阀
            });
            // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放
            circle++;
            // 如果circle == 6 说明走到最后克隆的这张图片 我们就复原为0
            if (circle == ol.children.length) {
                circle = 0;
            }
            //调用函数
            circleChange();
        }

As a result, the effect of the carousel image on the webpage is basically perfect, let’s take a look at the effect

Do you have the feeling of the graphic video in Douyin? That is also a carousel.

 PS: The complete JavaScript code is as follows:

window.addEventListener('load', function () {
    // 1. 获取元素
    var prev = document.querySelector('.prev');
    var next = document.querySelector('.next');
    var focus = document.querySelector('.focus');
    var focusWidth = focus.offsetWidth;// 获取图片的宽度
    // 2. 鼠标经过focus 就显示隐藏左右按钮
    focus.addEventListener('mouseenter', function () {
        prev.style.display = 'block';
        next.style.display = 'block';
        clearInterval(timer);
        timer = null;// 清除定时器变量
    })
    focus.addEventListener('mouseleave', function () {
        prev.style.display = 'none';
        next.style.display = 'none';
        timer = setInterval(function () {
            // 手动调用右侧按钮点击事件
            next.click();
        }, 2000)
    })
    // 3.动态生成小圆圈  有几张图片,就生成几张小圆圈
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('.circle');
    // console.log(ul.children.length);
    for (var i = 0; i < ul.children.length; i++) {
        // 创建一个小 li
        var li = document.createElement('li');
        // 记录当前小圆圈的索引号 通过自定义属性来做
        li.setAttribute('index', i);
        // 把小 li 插入到 ol 里面
        ol.appendChild(li);
        // 4. 小圆圈的排他思想 我们可以直接在生成小圆圈的同时直接绑定点击事件
        li.addEventListener('click', function () {
            // 干掉所有人 把所有的小 li 清除 current 类名
            for (var i = 0; i < ol.children.length; i++) {
                ol.children[i].className = '';
            }
            // 留下我自己 当前的小 li 设置 current 类名
            this.className = 'current';
            // 5. 点击小圆圈,移动图片,当然移动的是 ul
            // ul 的移动距离 = 小圆圈的索引号 乘以 图片的宽度 注意是负值
            // 当我们点击了某个小 li 就拿到当前小 li 的索引号
            var index = this.getAttribute('index');
            // 当我们点击了某个小 li 就要把这个 li 的索引号给 num 和 circle
            num = circle = index;
            // console.log(focusWidth);
            animate(ul, -index * focusWidth);
        })
    }
    // 把 ol 里面的第一个小 li 设置类名为 current
    ol.children[0].className = 'current';
    // 6. 克隆第一张图片(li)放到最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    // 7. 点击右侧按钮,图片滚动一张
    var num = 0;
    // 声明一个变量 circle 控制小圆圈的播放
    var circle = 0;
    // flag 节流阀
    var flag = true;
    next.addEventListener('click', function () {
        // 如果走到了最后复制的一张图片,此时 ul 要快速复原 left 改为 0
        if (flag) {
            flag = false;//关闭节流阀
            if (num == ul.children.length - 1) {
                ul.style.left = 0 + 'px';
                num = 0;
            }
            num++;
            animate(ul, -num * focusWidth, function () {
                flag = true;//打开节流阀
            });
            // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放
            circle++;
            // 如果circle == 6 说明走到最后克隆的这张图片 我们就复原为0
            if (circle == ol.children.length) {
                circle = 0;
            }
            //调用函数
            circleChange();
        }
    })

    // 9. 左侧按钮做法
    prev.addEventListener('click', function () {
        if (flag) {
            if (num == 0) {
                num = ul.children.length - 1;
                ul.style.left = -num * focusWidth + 'px';
            }
            num--;
            animate(ul, -num * focusWidth, function () {
                flag = true;
            });
            circle--;
            // 如果circle < 0 说明第一张图片 则小圆圈要改为第6个小圆圈
            if (circle < 0) {
                circle = ol.children.length - 1;
            }
            // 调用函数
            circleChange();
        }
    })

    // 优化代码,封装函数
    function circleChange() {
        for (var i = 0; i < ol.children.length; i++) {
            ol.children[i].className = '';
        }
        // 留下当前的小圆圈的current类名
        ol.children[circle].className = 'current';
    }

    // 10. 自动播放轮播图
    var timer = setInterval(function () {
        // 手动调用右侧按钮点击事件
        next.click();
    }, 2000)
})

★★★ Welcome to criticize and correct!

Guess you like

Origin blog.csdn.net/weixin_44566194/article/details/126953789