面向对象编程 JS 原生实现轮播图效果
1. 先看效果图
2. 需要实现的功能:
自动轮播
点击左右箭头按钮无缝轮播
点击数字按钮切换图片
分析: 如何实现无缝轮播?
在一个固定大小的相框里有一个 ul 标签, 其长度是几个图片宽度的总和, 通过 translateX() 的方法来实现左右移动动画.
如何实现无缝呢? 比如有三张图片, 可以在把第一张图片通过 cloneNode 的方法克隆下来放到第三张图片后面. 图片顺序 1,2,3,1, 看下面的 html 结构, 结构中并没有 4 张图, 第四张图是生成的.
3.HTML 结构
- <!-- ul 是图片盒子, ol 是数字按钮盒子, 最下面的 div 是左右箭头按钮盒子 -->
- <div class="container">
- <div id="screen">
- <ul>
- <li><img src="./img/1.jpg" alt=""></li>
- <li><img src="./img/2.jpg" alt=""></li>
- <li><img src="./img/3.jpg" alt=""></li>
- </ul>
- <ol>
- <!--<li class="active">1</li>-->
- <!--<li>2</li>-->
- <!--<li>3</li>-->
- </ol>
- </div>
- <div>
- <span><</span>
- <span>></span>
- </div>
- </div>
4. 功能实现
4.1 创建对象
创建一个对象, 需要传入一个相框盒子元素, 通过这个元素来获取盒子中其他需要的元素, 并把这些作为这个 Carousel 对象的属性:
- function Carousel(el) {
- this.screen = el; // 相框
- this.width = this.screen.offsetWidth; // 相框宽度
- this.ulBox = this.screen.children[0]; // ul 盒子
- this.list = this.ulBox.children; // ul 下面所有 li
- this.olBox = this.screen.children[1]; // 数字按钮盒子
- this.arrow = this.screen.nextElementSibling; // 箭头盒子
- this.leftArraw = this.arrow.children[0]; // 左箭头
- this.rightArraw = this.arrow.children[1]; // 右箭头
- this.index = 0; // 数字按钮的索引
- this.timeId = null; // 定时器的 id
- this.activeClass = 'active'; // 数字按钮 class 名
- this.durtion = '.35s'; // 动画持续时间
- }
4.2 动画效果由 translateX 实现
- // 动画
- Carousel.prototype.animate = function (target) {
- this.ulBox.style.transform = 'translateX(' + target + 'px)'
- };
4.3 根据轮播图片个数生成数字按钮节点
生成节点后, 为新生成的节点添加点击事件, 实现每次点击根据节点对应的 index 切换图片, 这里实现的需求的第三个功能.
- // 创建节点
- Carousel.prototype.createNodes = function () {
- let self = this;
- // 创建按钮节点
- for (let i = 0; i < self.list.length; i++) {
- let liObj = document.createElement('li');
- liObj.innerText = i + 1;
- self.olBox.appendChild(liObj);
- // 为生成的数字按钮添加点击事件
- liObj.onclick = function () {
- self.index = this.innerText - 1; // 获取当前点击对象的索引值
- self.switch_sel();
- self.animate(-self.index * self.width);
- };
- }
- // 默认显示第一张图片, 第一个数字按钮默认选中状态
- self.olBox.children[0].className = self.activeClass;
- // 克隆第一张图放到 ulBox 后面, 实现无缝轮播
- self.ulBox.appendChild(self.ulBox.children[0].cloneNode(true));
- };
4.4 轮播图数字按钮点击切换状态
因为多次用到这段代码, 所有就写成一个方法挂在 Carousel 对象上了
- // 切换数字按钮的选中状态
- Carousel.prototype.switch_sel = function(){
- let self = this;
- for (let i = 0; i < self.olBox.children.length; i++) {
- self.olBox.children[i].removeAttribute('class');
- }
- self.olBox.children[self.index].className = self.activeClass;
- };
4.5 轮播事件, 也是点击右箭头的事件
- // 轮播事件
- Carousel.prototype.clickHandle = function () {
- let self = this;
- // 如果是最后一张图, 直接跳到第一张
- if (self.index === self.list.length - 1) {
- self.index = 0;
- // 当点击到最后一张时直接跳到第一张
- self.ulBox.style.transitionDuration = '0s';
- self.animate(-self.index * self.width);
- }
- // 必须有时间延迟, 否则图片跳转切换不成功, 因为 self.animate() 没有来得及执行就被后面的 self.animate() 函数覆盖了.
- setTimeout(function () {
- self.ulBox.style.transitionDuration = self.durtion;
- self.index++;
- self.animate(-self.index * self.width);
- // 如果是最后一张图, 则去掉最后一个的 class 属性, 切换到第一个
- if (self.index === self.list.length - 1) {
- self.olBox.children[self.olBox.children.length - 1].removeAttribute('class');
- self.olBox.children[0].className = self.activeClass;
- } else { // 切换当前选中状态
- self.switch_sel();
- }
- }, 20);
- };
4.6 事件绑定
为左右箭头点击绑定事件, 同时当鼠标 hover 在相框上时自动轮播取消, 鼠标离开相框时自动轮播开始执行.
- // 事件绑定
- Carousel.prototype.bindEvent = function () {
- let self = this;
- // 又点击下一张
- self.rightArraw.onclick = function () {
- self.clickHandle();
- };
- // 左点击上一张
- self.leftArraw.onclick = function(){
- if(self.index === 0){
- self.index = self.list.length - 1;
- // 直接跳到最后一张
- self.ulBox.style.transitionDuration = '0s';
- self.animate(-self.index * self.width);
- }
- setTimeout(function(){
- self.ulBox.style.transitionDuration = self.durtion;
- self.index--;
- self.animate(-self.index * self.width);
- self.switch_sel();
- }, 20);
- };
- // 鼠标悬停清除定时器
- self.screen.parentElement.onmouseover = function(){
- self.timeId && clearInterval(self.timeId);
- self.arrow.style.display = 'flex';
- };
- // 鼠标离开打开定时器
- self.screen.parentElement.onmouseout = function(){
- self.timeId = setInterval(self.clickHandle.bind(self), 2000);
- self.arrow.style.display = 'none';
- }
- };
4.7 初始化方法
初始化方法中创建节点, 绑定事件, 同时设定定时器实现自动轮播效果.
- // 初始化
- Carousel.prototype.init = function () {
- this.createNodes();
- this.bindEvent();
- this.timeId = setInterval(this.clickHandle.bind(this), 2000);
- // 注意这里要 bind(this) 否则 clickHandle 中的 this 指向 Windows
- };
4.8 实例化 Carousel 对象, 大功告成
实例化一个轮播图对象, 然后调该对象的 init 方法.
只要 HTML 结构相同, 只需要传入不同的相框元素, 就可以在同一个页面中实例化多个轮播图对象. 也就是说, 同一个页面的多处轮播效果.
- let carousel = new Carousel(document.getElementById('screen'));
- carousel.init();
5 备注
全部的代码和 CSS 样式可参考我的 GitHub 中的轮播图仓库, 菜鸟程序猿一枚, 程序设计如果有不妥的地方欢迎提出意见或建议, 当然啦, 如果你喜欢并 star 了我的这个仓库, 我会很开心的 : )
[1]: https://github.com/jiangleiundo/carousel
来源: http://www.bubuko.com/infodetail-3048305.html