原生js写菜单栏滑块动画+Banner滑动效果(清晰思路+附代码)

一、实现效果

二、思路

1、核心animate.js动画js

单独做一个动画的js,动画都是基于这个函数,用的时候调用即可,animate(obj, target, callback) 函数有三个形参,obj为动画的对象,target为目标动画移动距离,callback为动画执行完在之后的回调函数。

//动画函数
//obj 动画绑定对象   traget 目标移动距离   callback回调函数
function animate(obj, target, callback) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
        //步长 = (目标值-现在位置)/10  取整
        let step = (target - obj.offsetLeft) / 10;
        //大于0向上取整   小于0向下取整
        step = step > 0 ? Math.ceil(step) : Math.floor(step);
        if (obj.offsetLeft == target) {
            //停止动画定时器
            clearInterval(obj.timer);
            //判断回调函数是否存在
            if (callback) {
                callback();
            }
        }
        obj.style.left = obj.offsetLeft + step + 'px';
    }, 15)
}
2、菜单栏滑块效果

nav
1、html布局:单独布局一个div盒子作为滑块


2、滑块js

(1)鼠标移入移出调用animate函数来执行动画,并且对应的菜单字体颜色变色
(2)鼠标点击后滑块停止在点击的菜单下面,字体变色,鼠标继续滑动会以目前点为初始点进行滑动,这里定义一个参数来接收点击的位置元素的offsetLeft

//菜单栏滑动块
    let cloud = document.querySelector('.cloud');
    let nav = document.querySelector('.nav');
    let lis = nav.querySelectorAll('li');
    let current = 0; //起始位置
    for (let i = 0; i < lis.length; i++) {
        lis[i].addEventListener('mouseenter', function() {
            animate(cloud, this.offsetLeft);
        })
        lis[i].addEventListener('mouseleave', function() {
            animate(cloud, current);
        })
        lis[i].addEventListener('click', function() {
            for (let i = 0; i < lis.length; i++) {
                lis[i].style.color = '';
            }
            lis[i].style.color = '#00BFFF'
            current = this.offsetLeft;
        })

    }

3、Banner

banner滑动布局原生js写菜单栏滑块动画+Banner滑动效果(清晰思路+附代码)_第1张图片
1、小图标
(1)根据图片数量动态生成小图标按钮,获取图片的ul.children.length,来动态生成li标签
(2)鼠标移入变色,排他原则
(3)鼠标划入那个小图标,banner图片会滑动到那张,通过小图标序号i * 图片宽度来实现banner图片的滑动效果

for (let i = 0; i < ul.children.length; i++) {
        let li = this.document.createElement('li');
        ol.appendChild(li);
        li.setAttribute('index', i)
        li.addEventListener('mouseover', function() {
            for (let i = 0; i < ol.children.length; i++) {
                ol.children[i].style.backgroundColor = 'white';
            }
            this.style.backgroundColor = '#00BFFF';
            animate(ul, -imgWidth * i)
            let index = this.getAttribute('index');
            num = index;
            circle = index;
        })
    }
    ol.children[0].style.backgroundColor = '#00BFFF';

2、左右按钮
(1)点击左右按钮,图片滑动,定义一个参数num,滑动距离=num*图片宽度
(2)点击左右按钮后num++,并且小按钮也跟随变化,定义变量circle,要保持两者一致,去一个中间变量index来保持numcircle一致,index可以定义index属性:li.setAttribute('index', i)
原生js写菜单栏滑块动画+Banner滑动效果(清晰思路+附代码)_第2张图片
(3)防抖,当点击左右按钮过快会出现图片滑动变快,可以定义一个flag = true来作为节流阀
首先判断flag,进入后先将flag = false,在动画执行完之后,回调函数callback里面将flag = true
(4)banner滑动无缝衔接,当滑动到在最后一张图片时候,需要有个判断,跳到第一张,这里在最后一个li加入第一张图片的li,即可实现无缝衔接。加入最后一个li可以采用动态添加节点的方式,克隆第一个节点。

//克隆第一张图片放在最后节点上面
    let firstImg = ul.children[0].cloneNode(true);
    ul.appendChild(firstImg);
if (num == ul.children.length - 1) {
                ul.style.left = 0; //没有动画效果,直接跳到第一张图片
                num = 0;
            }
//  封装右按钮函数
    function arrow_right() {
        if (flag) { //防抖
            flag = false
            if (num == ul.children.length - 1) {
                ul.style.left = 0;
                num = 0;
            }
            num++;
            animate(ul, -num * imgWidth, function() {
                flag = true;
            })
            circle++;
            if (circle == ol.children.length) {
                circle = 0;
            }
            for (let i = 0; i < ol.children.length; i++) {
                ol.children[i].style.backgroundColor = 'white';
            }
            ol.children[circle].style.backgroundColor = '#00BFFF';
        }

    }
    //封装左按钮函数
    function arrow_left() {
        if (flag) { //防抖
            flag = false;
            if (num == 0) {
                num = ul.children.length - 1;
                ul.style.left = -num * imgWidth + 'px';
            }
            num--;
            animate(ul, -num * imgWidth, function() {
                flag = true;
            })
            if (circle == 0) {
                circle = ol.children.length;
            }
            circle--;
            for (let i = 0; i < ol.children.length; i++) {
                ol.children[i].style.backgroundColor = 'white';
            }
            ol.children[circle].style.backgroundColor = '#00BFFF';
        }
    }

3、定时播放banner

timer = setInterval(arrow_right, 2500);

4、鼠标移入停止定时器,移出开启定时器

鼠标移入左右按钮出现

bannerimg.addEventListener('mouseover', function() {
        arrow_l.style.display = 'block';
        arrow_r.style.display = 'block';
        clearInterval(timer);
        timer = null;
    })
bannerimg.addEventListener('mouseout', function() {
        arrow_l.style.display = 'none';
        arrow_r.style.display = 'none';
        timer = setInterval(arrow_right, 2500);
    })

附录:
HTML:


"en">


    "UTF-8">
    "X-UA-Compatible" content="IE=edge">
    "viewport" content="width=device-width, initial-scale=1.0">
    Complexbanner
    "stylesheet" href="./banner.css">
    "stylesheet" href="./img/font-awesome-4.7.0/css/font-awesome.min.css">
    
    



    

CSS:

* {
    margin: 0 auto;
    padding: 0 auto;
}

a {
    text-decoration: none;
    color: black;
}

.contain {
    text-align: center;
    margin: 0 auto;
    padding: 0 auto;
}


/* header头部 */

.header {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 999;
    height: 50px;
    width: 100%;
    background-color: white;
    box-shadow: 0px 2px 8px 0px rgb(0 0 0 / 15%);
}

.nav {
    margin-left: 25%;
    width: 1500px;
    height: 50px;
    line-height: 50px;
}

.header .nav ul li {
    float: left;
    list-style: none;
    margin: 0 20px;
    height: 47px;
    width: 80px;
}

.header .nav ul li:hover {
    color: #00BFFF;
}

.cloud {
    height: 3px;
    width: 80px;
    background-color: #00BFFF;
    /* margin-left: 28.2%; */
    position: absolute;
    left: 536px;
    top: 47px;
}


/* benner部分 */

.bannerimg {
    position: relative;
    left: -40px;
    top: 0;
    width: 1960px;
    height: 660px;
    /* overflow: hidden; */
    /* border: 4px solid red; */
    /* z-index: 1000; */
    /* padding-left: -100px; */
}

.bannerimg img {
    /* margin-left: -40px; */
    width: 1960px;
    height: 660px;
    margin: 0;
    padding: 0;
}

.bannerimg ul {
    width: 900%;
    height: 660px;
    position: absolute;
    left: 0;
    top: 0;
    /* background-color: pink; */
    margin: 0;
    padding: 0;
}

.bannerimg ul li {
    float: left;
    list-style: none;
}

.arrow-l {
    position: absolute;
    left: 50px;
    top: 50%;
    color: rgba(255, 255, 255, .8);
    display: none;
    z-index: 999;
}

.arrow-l :hover {
    color: white;
}

.arrow-r {
    position: absolute;
    right: 16px;
    top: 50%;
    color: rgba(255, 255, 255, .8);
    display: none;
    z-index: 999;
}

.arrow-r :hover {
    color: white;
}

.bannerimg ol {
    position: absolute;
    left: 40%;
    bottom: 2%;
    width: 500px;
    height: 40px;
    z-index: 99;
}

.current {
    background-color: red;
}

.circle li {
    /* position: absolute;
    left: 50%;
    bottom: 10%; */
    width: 50px;
    height: 2px;
    background-color: white;
    cursor: pointer;
    margin: 0 10px;
    float: left;
    list-style: none;
}

JS:
1、动画animate.js

//动画函数
//obj 动画绑定对象   traget 目标移动距离   callback回调函数

function animate(obj, target, callback) {

    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
        //步长 = (目标值-现在位置)/10  取整
        let step = (target - obj.offsetLeft) / 10;
        //大于0向上取整   小于0向下取整
        step = step > 0 ? Math.ceil(step) : Math.floor(step);
        if (obj.offsetLeft == target) {
            //停止动画定时器
            clearInterval(obj.timer);

            if (callback) {
                callback();
            }
        }
        obj.style.left = obj.offsetLeft + step + 'px';
    }, 15)
}

2、banner.js

window.addEventListener('load', function() {
    let bannerMain = document.querySelector('.bannerMain');
    let bannerimg = document.querySelector('.bannerimg');
    let ul = bannerimg.querySelector('ul');
    let ol = bannerimg.querySelector('ol');
    arrow_l = document.querySelector('.arrow-l');
    arrow_r = document.querySelector('.arrow-r');
    img = bannerimg.querySelector('img');

    //菜单栏滑动块
    let cloud = document.querySelector('.cloud');
    let nav = document.querySelector('.nav');
    let lis = nav.querySelectorAll('li');
    let current = 0; //起始位置
    for (let i = 0; i < lis.length; i++) {
        lis[i].addEventListener('mouseenter', function() {
            animate(cloud, this.offsetLeft);
        })
        lis[i].addEventListener('mouseleave', function() {
            animate(cloud, current);
        })
        lis[i].addEventListener('click', function() {
            for (let i = 0; i < lis.length; i++) {
                lis[i].style.color = '';
            }
            lis[i].style.color = '#00BFFF'
            current = this.offsetLeft;
        })
    }

    //图片的宽度
    let imgWidth = img.offsetWidth;
    //num为左右按钮计数
    let num = 0;
    //circle为小图标计数
    let circle = 0;
    let flag = true; //节流阀 防抖
    //鼠标放在banner上面显示左右按钮
    bannerimg.addEventListener('mouseover', function() {
        arrow_l.style.display = 'block';
        arrow_r.style.display = 'block';
        clearInterval(timer);
        timer = null;
    })

    bannerimg.addEventListener('mouseout', function() {
        arrow_l.style.display = 'none';
        arrow_r.style.display = 'none';
        timer = setInterval(arrow_right, 2500);

    })
    //动态生成小圆圈  绑定事件
    for (let i = 0; i < ul.children.length; i++) {
        let li = this.document.createElement('li');
        ol.appendChild(li);
        li.setAttribute('index', i)

        li.addEventListener('mouseover', function() {
            for (let i = 0; i < ol.children.length; i++) {
                ol.children[i].style.backgroundColor = 'white';
            }
            this.style.backgroundColor = '#00BFFF';

            animate(ul, -imgWidth * i)
            let index = this.getAttribute('index');

            num = index;
            circle = index;
        })
    }
    ol.children[0].style.backgroundColor = '#00BFFF';

    //克隆第一张图片放在最后节点上面
    let firstImg = ul.children[0].cloneNode(true);
    ul.appendChild(firstImg);
    //左右按钮移动轮播图
    arrow_r.addEventListener('click', arrow_right)
    arrow_l.addEventListener('click', arrow_left)

    //自动轮播
    timer = setInterval(arrow_right, 2500);

    //  封装右按钮函数
    function arrow_right() {
        if (flag) { //防抖
            flag = false
            if (num == ul.children.length - 1) {
                ul.style.left = 0;
                num = 0;
            }
            num++;
            animate(ul, -num * imgWidth, function() {
                flag = true;
            })

            circle++;
            if (circle == ol.children.length) {
                circle = 0;
            }
            for (let i = 0; i < ol.children.length; i++) {
                ol.children[i].style.backgroundColor = 'white';
            }
            ol.children[circle].style.backgroundColor = '#00BFFF';
        }
    }

    //封装左按钮函数
    function arrow_left() {
        if (flag) { //防抖
            flag = false;
            if (num == 0) {
                num = ul.children.length - 1;
                ul.style.left = -num * imgWidth + 'px';

            }
            num--;
            animate(ul, -num * imgWidth, function() {
                flag = true;
            })
            if (circle == 0) {
                circle = ol.children.length;
            }
            circle--;
            for (let i = 0; i < ol.children.length; i++) {
                ol.children[i].style.backgroundColor = 'white';
            }
            ol.children[circle].style.backgroundColor = '#00BFFF';
        }
    }
})

你可能感兴趣的:(前端学习,javascript,动画,前端)