手写原生JS轮播图

轮播图也称为焦点图,是网页中比较常见的网页特效

本文主要制作6个效果
效果1:
当鼠标移入轮播图时,左右箭头显示出来,离开隐藏左右按钮
效果2:
点击小圆点就会弹出相应的图片
效果3:
点击轮播图左右按钮就会有图片改变的效果
效果4:
图片和下面的小圆点会对应同步变化
效果5:
鼠标不经过轮播图,则图片会自动滚动播放
效果6:
鼠标经过轮播图模块,自动播放停止
7:
制作一个节流阀以防点击过快

制作效果前:

分析结构:

手写原生JS轮播图_第1张图片

分为四个部分:大盒子,图片、左右按钮和小圆圈

准备好CSS和HTML:

HTML:


修改父级盒子的大小和图片盒子大小相同,因为考虑到可视性的原因,将图片大小统一改成800×600,因此父级盒子的大小也相应修改

CSS:

引入base.css

/* 引入base.css */

/*清除元素默认的内外边距  */
* {
    margin: 0;
    padding: 0
}
/*让所有斜体 不倾斜*/
em,
i {
    font-style: normal;
}
/*去掉列表前面的小点*/
li {
    list-style: none;
}
/*图片没有边框   去掉图片底侧的空白缝隙*/
img {
    border: 0;  /*ie6*/
    vertical-align: middle;
}
/*让button 按钮 变成小手*/
button {
    cursor: pointer;
}
/*取消链接的下划线*/
a {
    color: #666;
    text-decoration: none;
}

a:hover {
    color: #e33333;
}

引入轮播图的css:

.focus {
    position: relative;
    width: 800px;
    height: 600px;
    background-color: purple;
    margin: 0 auto;
}


.focus ul {
    position: absolute;
    top: 0;
    left: 0;
    /* 增加父盒子宽度,让父盒子能容下儿子 */
    width: 600%;
}


.focus ul li {
    /* 只写这个不会浮动起来,因为父盒子太小了容不下 */
    float: left;
}

制作效果一:

当鼠标移入轮播图时,左右箭头显示出来,离开隐藏左右按钮

首先给左右箭头添加display: none;,让它默认不显示

/* 左右箭头的盒子 */
.arrow-l,
.arrow-r {
/* 新增 */
    display: none;
...
}

分析js逻辑:

鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。

然后在js中写入以下代码:

// 1.获取元素

var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var focus = document.querySelector('.focus');

// 2.鼠标经过focus 就显示左右按钮

focus.addEventListener('mouseenter', function () {
    arrow_l.style.display = 'block';
    arrow_r.style.display = 'block';
})

focus.addEventListener('mouseleave', function () {
    arrow_l.style.display = 'none';
    arrow_r.style.display = 'none';
})

制作效果二:

点击小圆点就会弹出相应的图片

制作动态生成小圆圈

分析js逻辑:

  1. 核心思路:小圆圈的个数要跟图片张数要跟图片张数一致
  2. 所以首先先得到ul里面图片的张数(图片放入li里面,所以就是li 的个数)
  3. 利用循环动态生成小圆圈(这个小圆圈要放入ol里面)
  4. 创建createElement(‘li’),插入节点ol.appendChild(‘li’)
  5. 第一个小圆圈需要添加current类

写js之前,先完善一下CSS

加入:

.circle {
    position: absolute;
    bottom: 10px;
    left: 50px;
}

.circle li {
    float: left;
    width: 8px;
    height: 8px;
    border: 2px solid rgba(255, 255, 255, 0.5);
    margin: 0 3px;
    /* 显示为圆形 */
    border-radius: 50%;
    /*鼠标经过显示小手*/
    cursor: pointer;
}

/* 被选中的小圆圈的状态 */
.current {
    background-color: #fff;
}

然后在js中写入以下代码:

// 3. 动态生成小圆圈, 有几张图片,就生成几个小圆圈
var ul = focus.querySelector('ul');
console.log(ul.children.length); // 4个
var ol = focus.querySelector('.circle');
for (var i = 0; i < ul.children.length; i++) {
    // 创建一个小li
    var li = document.createElement('li');
    // 把小li插入到ol里面
    ol.appendChild(li);
}
// 把ol里面的第一个小li设置类名为 current
ol.children[0].className = 'current';

手写原生JS轮播图_第2张图片

制作点击小圆圈就切换current属性

分析js逻辑:

  1. 排他思想:干掉所有人,留下我自己
  2. 排他思想放在for循环里,生成了之后就可以直接进行操作
  3. 效果:点击某个小按钮则变成白色,其他全部变成透明的

然后在js中写入以下代码:

记得放在for循环中

// 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';
})

制作点击小圆圈实现滑动的效果

分析js逻辑:

  1. 点击小圆圈实现滑动的效果
  2. 此时要用到animate动画函数,记得一定要将引入animate的js文件引入在index.js文件之前(因为有调用的效果)
  3. 使用动画函数的前提,该元素必须要有定位
  4. 图片动是ul动,而不是li动
  5. 滚动图片的核心算法:点击某个小圆圈,就让图片滚动小圆圈的索引号乘以图片的宽度作为ul移动距离
  6. 此时需要知道小圆圈的索引号,可以在生成小圆圈的时候,给它设置一个自定义属性,点击的时候获取这个自定义属性即可。

animate动画函数:

function animate(obj, target, callback) {
    // console.log(callback);  callback = function() {}  调用的时候 callback()

    // 先清除以前的定时器,只保留当前的一个定时器执行
    clearInterval(obj.timer);
    obj.timer = setInterval(function () {
        // 步长值写到定时器的里面
        // 把我们步长值改为整数 不要出现小数的问题
        // var step = Math.ceil((target - obj.offsetLeft) / 10);
        var step = (target - obj.offsetLeft) / 10;
        step = step > 0 ? Math.ceil(step) : Math.floor(step);
        if (obj.offsetLeft == target) {
            // 停止动画 本质是停止定时器
            clearInterval(obj.timer);
            // 回调函数写到定时器结束里面
            // if (callback) {
            //     // 调用函数
            //     callback();
            // }
            callback && callback();
        }
        // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
        obj.style.left = obj.offsetLeft + step + 'px';

    }, 15);
}

然后在js中写入以下代码:

写在循环外:
// 记录当前小圆圈的索引号,通过自定义属性来做
li.setAttribute('index', i);

循环内:
// 5.点击小圆圈,移动图片 当然移动的是 ul
// ul移动的距离:小圆圈的索引号 * 图片的宽度 注意是负值
// 获取图片的宽度
var focusWidth = focus.offsetWidth;
// 当我们点击了某个 小li ,就拿到当前小li的索引号
var index = this.getAttribute('index'); // 0 1 2 3 得到的是自定义属性index的具体的值
var target = -index * focusWidth;
animate(ul, target);

这样,就可以做到点击小圆圈就缓动到当前图片的效果了。
但是全屏显示后发现其他图片却没有隐藏

在CSS中加入:

/* 最外层包裹的盒子 */
.focus {
    position: relative;
    width: 800px;
    height: 600px;
    background-color: purple;
    margin: 0 auto;
    /* 新加,以隐藏多余的 */
    overflow: hidden;
}

即可隐藏~

制作效果三:

点击轮播图左右按钮就会有图片改变的效果

分析js逻辑:

  1. 点击右侧按钮一次,就让图片滚动一张
  2. 声明一个变量num、点击一次就自增1,让这个变量乘以图片宽度,就是ul的滚动效果
  3. 图片无缝滚动原理:把ul的第一个复制一份,放到ul的最后面;当图片滚动到克隆的最后一张图片时,让ul快速的、不做动画的跳到最左侧:left为0。
  4. 但是注意把克隆节点写在生成小圆圈的后面,所以不会生成小圆圈
  5. 同时num赋值为0,就可以重新开始滚动图片了

然后在js中写入以下代码:

//7.克隆第一张图片 放到ul最后面
var first = ul.children[0].cloneNode(true);
ul.appendChild(first);

使用深克隆:cloneNode(true)

//点击轮播图左右按钮就会有图片改变的效果
var num = 0;
arrow_r.addEventListener('click', function () {
    // 如果走到了最后复制的一张图片,此时我们的ul要快速复原 left改为0
    if (num === ul.children.length - 1) {
        num = 0;
        ul.style.left = 0;
    }
    num++;
    animate(ul, -num * focus.offsetWidth);

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

制作效果四:

图片和下面的小圆点会对应同步变化

分析js逻辑:

  1. 点击右侧按钮,小圆圈跟随变化
  2. 最简单的办法就是再声明一个变量circle,每次点击就自增1,注意,左侧按钮也需要这个变量,因此要声明全局变量
  3. 但是图片有五张,小圆圈只有4个少一个,必须加一个判断条件:如果circle == 4 就重新复原为0
  4. 判断circle的方法要紧跟着circle定义写

然后在js中写入以下代码:

在arrow_r中添加:

// 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量circle控制小圆圈的播放
circle++;
if (circle == ol.children.length) {
    circle = 0;
}
circleChange();

在arrow_l中添加:

//  点击左侧按钮,小圆圈跟随一起变化,通过变量circle控制小圆圈的播放
circle--;
// 如果circle <0 说明是第一张图片,则小圆圈要改为第4个小圆圈(3)
if (circle < 0) {
    circle = ol.children.length - 1;
}
circleChange();

其中circleChange()方法为排他思想

function circleChange() {
    // 先清除其余小圆圈的current类名
    for (var i = 0; i < ol.children.length; i++) {
        ol.children[i].className = '';
    }
    // 留下当前小圆圈的current类名
    ol.children[circle].className = 'current';
}

最后:

把点击小圆圈和点击右按钮结合起来
也就是比如说当我们点击第三个小圆圈时,index=2,此时num也得=2

分别在
li.addEventListener('click', function (){})
中添加
// 当我们点击了某个小li 就要把这个li 的索引号给 num
num = index;

在
arrow_r.addEventListener('click', function () {})
和
arrow_l.addEventListener('click', function () {})
中添加

circle = num;

制作效果五:

鼠标不经过轮播图,则图片会自动滚动播放

分析js逻辑:

使用定时器方法

  1. 自动播放功能
  2. 添加一个定时器
  3. 自动播放轮播图,实际就类似于隔一段时间点击了右侧按钮
  4. 使用手动调用右侧按钮点击事件 arrow_r.click()
  5. 鼠标经过focus就停止定时器
  6. 鼠标离开focus就开启定时器

然后在js中写入以下代码:

// 10.自动播放轮播图
var timer = this.setInterval(function () {
    arrow_r.click();
}, 2000)

制作效果六:

鼠标经过轮播图模块,自动播放停止

分析js逻辑:

使用消除定时器方法

然后在js中写入以下代码:

在focus.addEventListener('mouseenter', function() {}) 中加入
        clearInterval(timer);
        timer = null; // 清除定时器变量

最后制作一个节流阀

防止轮播图按钮连续点击造成播放过快

分析js逻辑:

  1. 节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
  2. 核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数
  3. 开始设置一个变量 var flag = true;
  4. if(flag){flag = false;do something} 关闭水龙头
  5. 利用回调函数,当动画执行完毕,flag=true 打开水龙头

然后在js中写入以下代码:

在左右箭头外写入flag节流阀,内部进行判断

 // flag 节流阀
    var flag = true;
    arrow_r.addEventListener('click', function() {
        if (flag) {
				...
            }
        }
    });

arrow_l.addEventListener('click', function() {
    if (flag) {
        flag = false;
        ....
	}
});

在左右侧箭头点击的监听函数写入flag变量,设置为false。在animate函数中写入function回调函数打开节流阀(因为执行函数时动画已经结束了)

你可能感兴趣的:(javascript)