资讯专栏INFORMATION COLUMN

一款轮播插件的诞生

qianfeng / 1498人阅读

摘要:同理,向左轮播至第一张图片时,也会取消后轮播图定位至第六张图片而后再度开启。续判断是否开启自动轮播,如是则自动轮播加入事件监听监听鼠标移入事件,当鼠标移入的时候,停止自动滚动。监听左右按钮的点击,执行上一张,下一张图的轮播效果。

1. 前言

早在几个月前,就想自己动手写个轮播图组件,因此也看了许多文章,断断续续过了几个月,今天终于有时间腾出手来给此插件做个总结,因此有了这篇文章。话不多说,先上 Demo, 效果如下:

2. HTML and CSS

本文不讨论html,css的实现方式,直接贴上代码

  1. <span class="hljs-attr">Suporka</span> <span class="hljs-string">Vue App</span>
  2. <
  3. >

</>code

  1. /*样式代码*/
  2. * {
  3. margin: 0;
  4. padding: 0;
  5. }
  6. div {
  7. margin: 0;
  8. border: 0;
  9. padding: 0;
  10. }
  11. #carousal {
  12. width: 557px;
  13. overflow: hidden;
  14. position: relative;
  15. }
  16. #wrapper {
  17. display: box; /* OLD - Android 4.4- */
  18. display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
  19. display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
  20. display: -ms-flexbox; /* TWEENER - IE 10 */
  21. display: -webkit-flex; /* NEW - Chrome */
  22. display: flex;
  23. -webkit-flex-wrap: nowrap;
  24. -moz-flex-wrap: nowrap;
  25. -ms-flex-wrap: nowrap;
  26. -o-flex-wrap: nowrap;
  27. flex-wrap: nowrap;
  28. white-space: nowrap;
  29. position: relative;
  30. left: 0;
  31. }
  32. .suporka-carousel__arrow {
  33. /* display: none; */
  34. border: none;
  35. outline: none;
  36. padding: 0;
  37. margin: 0;
  38. height: 36px;
  39. width: 36px;
  40. cursor: pointer;
  41. transition: 0.3s;
  42. border-radius: 50%;
  43. background-color: rgba(31, 45, 61, 0.5);
  44. color: #fff;
  45. position: absolute;
  46. top: 50%;
  47. z-index: 10;
  48. transform: translateY(-50%);
  49. text-align: center;
  50. font-size: 12px;
  51. font-weight: 600;
  52. }
  53. .suporka-carousel__arrow--right {
  54. right: -38px;
  55. }
  56. .suporka-carousel__arrow--left {
  57. left: -38px;
  58. }
  59. #carousal:hover > .suporkal-carousel__arrow {
  60. display: block;
  61. }
  62. #carousal:hover .suporka-carousel__arrow--right {
  63. right: 16px;
  64. }
  65. #carousal:hover .suporka-carousel__arrow--left {
  66. left: 16px;
  67. }
  68. #suporka-dot {
  69. position: absolute;
  70. bottom: 20px;
  71. left: 50%;
  72. transform: translate(-50%, 0);
  73. }
  74. #suporka-dot span {
  75. width: 10px;
  76. height: 10px;
  77. border-radius: 50%;
  78. margin: 0 10px;
  79. display: inline-block;
  80. background: #999;
  81. }
  82. #suporka-dot .suporka-dot--acitve {
  83. background: #fff;
  84. }
3. javascript 实现轮播图功能

本插件是用 es6 写的,当然考虑兼容性,你可以选择 babel 进行编译,本文不做阐述。

1. 首先,创建一个 carousal 类

它有一些默认参数,如time(图片轮播间隔),transition (转场动画时间),autoScroll(是否自动轮播),showDot(是否显示底部小圆点)。然后将页面的一些元素挂载在类的属性上。

</>code

  1. class Carousal {
  2. constructor(userOption) {
  3. this.option = {
  4. time: 4000,
  5. transition: 0.8,
  6. autoScroll: true,
  7. showDot: false
  8. };
  9. // 当前索引
  10. this.number = 1;
  11. // 定时器
  12. this.timer = null;
  13. this.interval = null;
  14. this.carousal = document.getElementById("carousal");
  15. this.wrapper = document.querySelector("#wrapper");
  16. this.childrenLength: document.getElementById("wrapper").children.length;
  17. this.init(userOption);
  18. }
  19. }
2. 初始化dom

当然,默认参数是可以修改的,所以类传入了一个 userOption 对象, 在构造函数中将用户设置的参数覆盖默认参数,在this.init(userOption) 方法中执行覆盖。

轮播图轮播的原理是:在轮播图组首位添加一个末位图片的副本,同时也在轮播图末位添加一个首位图片的副本,大概就是 5 1 2 3 4 5 1 , 此时共有7张图片,当向右轮播至第七张图片‘1’ 时, 取消transition后轮播图定位至第二张图片 ‘1’, 此时再度开启transition 。同理,向左轮播至第一张图片“5”时,也会取消transition后轮播图定位至第六张图片 ‘5’, 而后再度开启 transition。

因此,我们需要手动在dom结构中插入这两个首尾图片。pushItem() 方法正是为此而生。

</>code

  1. class Carousal {
  2. //...
  3. init(userOption) {
  4. // 合并用户配置
  5. if (Object.assign) {
  6. Object.assign(this.option, userOption);
  7. } else {
  8. // 不支持 Object.assign 就调用 extend 方法
  9. this.extend(this.option, userOption, true);
  10. }
  11. // 设置动画 transition
  12. this.wrapper.style.transition = `all ${this.option.transition}s`;
  13. this.wrapper.style["-moz-transition"] = `all ${this.option.transition}s`;
  14. this.wrapper.style["-webkit-transition"] = `all ${this.option.transition}s`;
  15. this.wrapper.style["-o-transition"] = `all ${this.option.transition}s`;
  16. // 首尾添加元素
  17. this.pushItem();
  18. }
  19. // 合并属性方法
  20. extend(o, n, override) {
  21. for (var p in n) {
  22. if (n.hasOwnProperty(p) && (!o.hasOwnProperty(p) || override))
  23. o[p] = n[p];
  24. }
  25. }
  26. // 初始化添加首尾子元素
  27. pushItem() {
  28. let movePx = this.carousal.offsetWidth; // 获取轮播图宽度
  29. let first = this.wrapper.children[0].cloneNode(true);
  30. let last = this.wrapper.children[this.childrenLength - 1].cloneNode(true);
  31. let parent = this.wrapper;
  32. parent.appendChild(first);
  33. parent.insertBefore(last, parent.children[0]);
  34. this.wrapper.style.left =
  35. this.wrapper.offsetLeft - movePx + "px";
  36. }
  37. }

插入轮播图片之后,判断是否需要插入底部小圆点。requestAnimFrame()用于实现持续的动画效果。

</>code

  1. class Carousal {
  2. init() {
  3. //...续 this.pushItem();
  4. if (this.option.showDot) {
  5. let node = document.createElement("div");
  6. node.setAttribute("id", "suporka-dot");
  7. node.innerHTML = `${"".repeat(this.childrenLength)}`;
  8. this.carousal.appendChild(node);
  9. this.dot = document.getElementById("suporka-dot");
  10. this.dot.firstChild.setAttribute("class", "suporka-dot--acitve");
  11. }
  12. // 判断是否开启自动轮播,如是则自动轮播
  13. if (this.option.autoScroll) this.requestAnimFrame(this.autoMove());
  14. }
  15. requestAnimFrame() {
  16. return (
  17. window.requestAnimationFrame ||
  18. window.webkitRequestAnimationFrame ||
  19. window.mozRequestAnimationFrame ||
  20. window.oRequestAnimationFrame ||
  21. window.msRequestAnimationFrame ||
  22. function(callback) {
  23. window.setTimeout(callback, 1000 / 60);
  24. }
  25. );
  26. }
  27. }
3. 加入事件监听

监听鼠标移入事件,当鼠标移入的时候,停止自动滚动。

监听左右按钮的点击,执行上一张,下一张图的轮播效果。

</>code

  1. class Carousal {
  2. init() {
  3. //...续 if (this.option.autoScroll) this.requestAnimFrame(this.autoMove());
  4. this.addEventListener();
  5. }
  6. // 添加事件
  7. addEvent(element, type, handler) {
  8. if (element.addEventListener) {
  9. element.addEventListener(type, handler, false);
  10. } else if (element.attachEvent) {
  11. element.attachEvent("on" + type, handler);
  12. } else {
  13. element["on" + type] = handler;
  14. }
  15. }
  16. // 事件监听
  17. addEventListener() {
  18. if (this.option.autoScroll) {
  19. this.addEvent(this.carousal, "mouseover", event => {
  20. clearInterval(this.interval);
  21. });
  22. this.addEvent(this.carousal, "mouseout", event => {
  23. this.autoMove();
  24. });
  25. }
  26. let prev = document.getElementById("suporka-prev-btn");
  27. let next = document.getElementById("suporka-next-btn");
  28. if (prev && next) {
  29. this.addEvent(prev, "click", event => {
  30. this.prev();
  31. });
  32. this.addEvent(next, "click", event => {
  33. this.next();
  34. });
  35. }
  36. }
  37. }
4. 自动轮播

定时动画,并且如果存在底部小圆点,修改其类名,达到与轮播图同步的效果。

</>code

  1. // 自动轮播
  2. class Carousal {
  3. // ...
  4. autoMove() {
  5. let movePx = this.carousal.offsetWidth;
  6. this.interval = setInterval(() => {
  7. this.number += 1;
  8. this.wrapper.style.left = 0 - movePx * this.number + "px";
  9. if (this.number === this.childrenLength + 1) this.startMove();
  10. if (this.dot)
  11. this.setDotClass(
  12. this.dot.children,
  13. this.number - 1,
  14. "suporka-dot--acitve"
  15. );
  16. }, this.option.time);
  17. }
  18. // 开始移动
  19. startMove() {
  20. this.number = 1;
  21. this.timer = setTimeout(() => {
  22. this.wrapper.style.transition = `none`;
  23. this.wrapper.style.left = -this.carousal.offsetWidth + "px";
  24. setTimeout(() => {
  25. this.wrapper.style.transition = `all ${
  26. this.option.transition
  27. }s`;
  28. }, 100);
  29. }, this.option.transition * 1000);
  30. }
  31. // 设置小圆点样式
  32. setDotClass(parent, index, cls) {
  33. // 没有小圆点就返回
  34. if (!this.dot) return false;
  35. for (let i = 0; i < parent.length; i++) {
  36. removeClass(parent[i], cls);
  37. }
  38. addClass(parent[index], cls);
  39. }
  40. }
  41. // 三个类名操作方法
  42. function hasClass(ele, cls) {
  43. if (ele.className)
  44. return ele.className.match(new RegExp("(s|^)" + cls + "(s|$)"));
  45. else return false;
  46. }
  47. function addClass(ele, cls) {
  48. if (!hasClass(ele, cls)) ele.className += " " + cls;
  49. }
  50. function removeClass(ele, cls) {
  51. if (hasClass(ele, cls)) {
  52. let reg = new RegExp("(s|^)" + cls + "(s|$)");
  53. ele.className = ele.className.replace(reg, " ");
  54. }
  55. }
5. 实现上一张,下一张轮播功能

</>code

  1. class Carousal {
  2. //...
  3. // prev上一张
  4. prev() {
  5. let movePx = this.carousal.offsetWidth;
  6. this.number -= 1;
  7. this.wrapper.style.left = 0 - movePx * this.number + "px";
  8. if (this.number === 0) this.goLastOne();
  9. if (this.dot)
  10. this.setDotClass(
  11. this.dot.children,
  12. this.number - 1,
  13. "suporka-dot--acitve"
  14. );
  15. }
  16. // 下一张
  17. next() {
  18. let movePx = this.carousal.offsetWidth;
  19. this.number += 1;
  20. this.wrapper.style.left = 0 - movePx * this.number + "px";
  21. if (this.number === this.childrenLength + 1) this.startMove();
  22. if (this.dot)
  23. this.setDotClass(
  24. this.dot.children,
  25. this.number - 1,
  26. "suporka-dot--acitve"
  27. );
  28. }
  29. // 去到最后一张
  30. goLastOne() {
  31. this.number = this.childrenLength;
  32. this.timer = setTimeout(() => {
  33. this.wrapper.style.transition = `none`;
  34. this.wrapper.style.left =
  35. -this.carousal.offsetWidth * this.childrenLength + "px";
  36. setTimeout(() => {
  37. this.wrapper.style.transition = `all ${
  38. this.option.transition
  39. }s`;
  40. }, 100);
  41. }, this.option.transition * 1000);
  42. }
  43. }
4.优化及其他

最后,代码需经过babel转译,并且以 umd 的形式支持浏览器直接引入,requirejs 及 commonjs 导入,详细做法可以参考我之前的一篇文章《ES6 手写一个“辨色”小游戏》。也可以参考我在 github 上的代码, 欢迎 fork and star .

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100485.html

相关文章

  • swiper使用

    摘要:是一款轮播图插件,我是用在里面,方便省事儿。官网地址地址安装安装完成之后,我没有在中注册它,而是在使用页面注册的。因为通常来说轮播图只会在一个应用的首页展示,所以就没必要在全局注册它,只用在页面注册使用一下就可以了。 swipe是一款轮播图插件,我是用在vue里面,方便省事儿。swipe里面有很多关于滑动的组建,我只用过轮播图,如果以后有时间,可以再看看官网上别的组件介绍。官网地址 g...

    makeFoxPlay 评论0 收藏0
  • swiper使用

    摘要:是一款轮播图插件,我是用在里面,方便省事儿。官网地址地址安装安装完成之后,我没有在中注册它,而是在使用页面注册的。因为通常来说轮播图只会在一个应用的首页展示,所以就没必要在全局注册它,只用在页面注册使用一下就可以了。 swipe是一款轮播图插件,我是用在vue里面,方便省事儿。swipe里面有很多关于滑动的组建,我只用过轮播图,如果以后有时间,可以再看看官网上别的组件介绍。官网地址 g...

    MyFaith 评论0 收藏0
  • swiper使用

    摘要:是一款轮播图插件,我是用在里面,方便省事儿。官网地址地址安装安装完成之后,我没有在中注册它,而是在使用页面注册的。因为通常来说轮播图只会在一个应用的首页展示,所以就没必要在全局注册它,只用在页面注册使用一下就可以了。 swipe是一款轮播图插件,我是用在vue里面,方便省事儿。swipe里面有很多关于滑动的组建,我只用过轮播图,如果以后有时间,可以再看看官网上别的组件介绍。官网地址 g...

    aaron 评论0 收藏0
  • JavaScript精编干货

    摘要:老姚浅谈怎么学鉴于时不时,有同学私信问我老姚,下同怎么学前端的问题。撸码听歌,全局控制。 浅析用 js 解析 xml 的方法 由于项目上需要解析 xml,于是各种百度,然后自己总结了下各个主流浏览器解析 xml 的方法,只能是很浅显的知道他的用法,但是还没有深层次的研究。 装 X - 建立自己的斗图网站库 之前加过一个斗图群,看到很多经典的表情,然后就收藏到了 QQ, 迫于本屌丝开不起...

    Fourierr 评论0 收藏0
  • 前端常用插件、工具类库汇总

    摘要:页面调试腾讯开发维护的代码调试发布,错误监控上报,用户问题定位。同样是由腾讯开发维护的代码调试工具,是针对移动端的调试工具。前端业务代码工具库。动画库动画库,也是目前通用的动画库。 本人微信公众号:前端修炼之路,欢迎关注 本篇文章整理自己使用过的和看到过的一些插件和工具,方便日后自己查找和使用。 另外,感谢白小明,文中很多的工具来源于此。 弹出框 layer:http://layer....

    GitCafe 评论0 收藏0

发表评论

0条评论

qianfeng

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<