Vue如何制作图片轮播组件(附代码)

这次给大家带来Vue如何制作图片轮播组件(附代码),Vue制作图片轮播组件的注意事项有哪些,下面就是实战案例,一起来看一下。

在制作这个组件之前,笔者google了不少关于轮播的文章,发现实现一个轮播的思路虽然各有不同,但是大的逻辑其实差不多,本文主要依据慕课网上焦点轮播图特效这节课,不过慕课网主要用原生JS写,而笔者则用Vue进行了重构,并且进行了一点修改。完成后的组件效果图如下:

Vue如何制作图片轮播组件(附代码) 

一、理清思路,理解需求和原理

1. 要写一个什么样的轮播?

在点击右侧箭头时,图片向左滑动到下一张;点击左侧箭头时,图片向右滑到下一张

点击下面的小圆点,滑到对应的图片,相应小圆点的样式也发生改变

要有过渡效果,要缓缓滑动过去

当鼠标hover到图片上时,轮播暂停,当鼠标leave时,轮播继续

自动播放功能

无限滚动,即在滚动到最后一张时,再点击下一张时会继续向左滑动到第一张,而不是整个拉到第一张,这里有点难

2. 理解无限轮播的原理

我们先看下原理图:

Vue如何制作图片轮播组件(附代码) 

图中红线区域即是我们看到的图片,这个轮播 只展示5张图片 ,但是在它的首尾各还有两张图片,在图1前面放置了图5,在图5后面放置了图1,之所以这么做,是为了做无限滚动。 无限滚动的原理在于:当整个图向左侧滚动到右边的图5时,会继续向前走到图1,在完全显示出图1后,会以肉眼看不到的速度向右侧拉回到最左边的图1。 这样,即使再向左侧滑动看到的就是图2了。

如下图:在最后的图1完成过渡完全显示出来后,再将整个列表瞬间向右拉到左侧的图1。另一张边界图图5的滚动也是,不过方向相反。

Vue如何制作图片轮播组件(附代码)Vue如何制作图片轮播组件(附代码)

二、先让图片切换起来

1. 布局和准备

 

// window上图中红线框

    //注意这里的:style //这是图片列表,排成一排
  • //列表最前面的辅助图,它和图5一样,用于无限滚动 Vue如何制作图片轮播组件(附代码)
  • //通过v-for渲染的需要展示的5张图 Vue如何制作图片轮播组件(附代码)
  • //列表最后面的辅助图,它和图1一样,用于无限滚动 Vue如何制作图片轮播组件(附代码)
    //两侧的箭头
    //下面的小圆点

export default { name: 'slider', data () { return { sliders:[ { img:'../../static/images/1.jpg' }, { img:'../../static/images/2.jpg' }, { img:'../../static/images/3.jpg' }, { img:'../../static/images/4.jpg' }, { img:'../../static/images/5.jpg' } ], currentIndex:1, distance:-600 } }, computed:{ containerStyle() { //这里用了计算属性,用transform来移动整个图片列表 return { transform:`translate3d(${this.distance}px, 0, 0)` } } }}

登录后复制

好了,布局大概就是这样,效果图如下:

Vue如何制作图片轮播组件(附代码) 

上面的代码已经做了注释,有几个点在这里再提一下:

window是红线框, 宽度为600px ,它不会动,移动的是包裹着图片的container,它的移动方式用 :style=”containerStyle” ,这是一个计算属性,用 transform:translate3d(${this.distance, 0, 0}) 来控制左右移动

data里的 distance 和 currentIndex 是关键, distance 控制着移动的距离,默认是-600,显示7张图片中的第二张,也就是图1。 currentIndex 是window显示的图片的索引,这里默认是1,也是7张图片中第2张。

需要展示的只有5张图片,但是在图1前了一张图5、在图5后面放了一张图1来做无限滚动,原理前面说过了

当点击右侧的箭头,container向左移动, distance 会越来越小;当点击左侧的箭头,container向右移动, distance 会越来越大,方向不要弄错

2. 图片切换

我们在左侧和右侧的箭头上添加点击事件:

...... methods:{ move(offset, direction) { this.distance += this.distance * direction if (this.distance -600) this.distance = -3000 } }

登录后复制

解释下上面的代码:点击左侧或者右侧的箭头,调用move函数,move接收偏移量offset和方向direction两个参数。direction只传两个值,1表示container向右移动,-1表示container向左移动;偏移量是600,也就是一张图片的宽度。如果移动到7张图片的最后一张,就把container拉到7张图片里的第二张;如果移动到7张图片里第一张,就把container拉到7张图片里的第5张。

效果:

Vue如何制作图片轮播组件(附代码) 

可以看到,图片切换效果已经出来了,但是下面的小圆点没有跟着变换。接下来我们把这个效果加上。从上面的html代码可以看到, :class=”{dotted: i === (currentIndex – 1)}” ,小圆点的切换效果和data里的currentIndex值相关,我们只要随着图片切换变动currentIndex值就可以了。

修改move方法里的代码:

……

move(offset, direction) {  direction === -1 ? this.currentIndex++ : this.currentIndex--  if (this.currentIndex > 5) this.currentIndex = 1  if (this.currentIndex < 1) this.currentIndex = 5  this.distance = this.distance + offset * direction  if (this.distance  -600) this.distance = -3000  }

登录后复制

上面的添加的三行代码很好理解,如果是点击右侧箭头,container就是向左移动, this.currentIndex 就是减1,反之就是加1。

效果:

Vue如何制作图片轮播组件(附代码) 

可以看到,小圆点的切换效果已经出来了。

三、过渡动画

上面的代码已经实现了切换,但是没有动画效果,显的非常生硬,接下来就是给每个图片的切换过程添加过渡效果。

这个轮播组件笔者并没有使用Vue自带的class钩子,也没有直接使用css的transition属性,而是用慕课网原作者讲的setTimeout方法加递归来实现。

其实我也试过使用Vue的钩子,但是总有一些小问题解决不掉;比如下面找到的这个例子:例子

这个例子在过渡的边界上有一些问题,我也遇到了,而且还是时有时无。而如果使用css的transition过渡方法,在处理边界的无限滚动上总会在chrome浏览器上有一下闪动,即使添加了 -webkit-transform-style:preserve-3d; 和 -webkit-backface-visibility:hidden 也还是没用,而且要配合transition的 transitionend 事件对于IE浏览器的支持也不怎么好。

如果大家有看到更好的办法,请在评论中留言哦~

下面我们来写这个过渡效果,主要是改写:

methods:{  move(offset, direction) {    direction === -1 ? this.currentIndex++ : this.currentIndex--    if (this.currentIndex > 5) this.currentIndex = 1    if (this.currentIndex < 1) this.currentIndex = 5    const destination = this.distance + offset * direction    this.animate(destination, direction)  },  animate(des, direc) {    if ((direc === -1 && des  this.distance)) {      this.distance += 30 * direc          window.setTimeout(() => {        this.animate(des, direc)      }, 20)    } else {      this.distance = des      if (des  -600) this.distance = -3000   }  }}

登录后复制

上面的代码是这个轮播我觉得最麻烦、也是最难理解的地方。

来理解一下:首先,我们对于move方法进行了改写,因为要一点点的移动,所以要先算出要移动到的目标距离。然后,我们写一个animate函数来实现这个过渡。这个animate函数接收两个参数,一个是要移动到的距离,另一个是方向。 如果我们点击了右侧的箭头,container要向左侧移动,要是没有移动到目标距离,就在 this.distance 减去一定的距离,如果减去后还是没有到达,在20毫米以后再调用这个 this.animate ,如此不断移动,就形成了过渡效果。而如果移动到了目标距离,那就将目标距离赋值给 this.distance ,然后再进行边界和无限滚动的判断。

当然,使用 window.setInterval() 也可以实现这个效果,而且会稍微好理解一点,因为没有用到递归:

methods:{  move(offset, direction) {    direction === -1 ? this.currentIndex++ : this.currentIndex--    if (this.currentIndex > 5) this.currentIndex = 1    if (this.currentIndex  {      if ((direc === -1 && des  this.distance)) {        this.distance += 30 * direc      } else {        window.clearInterval(temp)        this.distance = des        if (des  -600) this.distance = -3000      }    }, 20)  } }

登录后复制

实现出来的效果如下:

Vue如何制作图片轮播组件(附代码) 

四、简单节流一下

写到这里,效果是出来了,但是会有一点问题,如果多次快速点击,就会有可能出现下面这种情况:

Vue如何制作图片轮播组件(附代码) 

出现这种情况的原因很简单,因为是使用定时器过渡,所以连续快速点击就会出现错乱,简单节流一下就好了: 在过渡完成之前点击箭头无效,其实就是设了一个闸,第一次点击把闸打开,在闸再次打开之前,让一部分代码无法执行,然后再在恰当的时机把闸打开。

我们把这个闸设在move函数里:

move(offset, direction) {  if (!this.transitionEnd) return //这里是闸  this.transitionEnd = false    //开闸以后再把闸关上  direction === -1 ? this.currentIndex++ : this.currentIndex--  if (this.currentIndex > 5) this.currentIndex = 1  if (this.currentIndex < 1) this.currentIndex = 5  const destination = this.distance + offset * direction  this.animate(destination, direction)}

登录后复制

this.transitionEnd 是这个闸的钥匙,我们把它放到data里:

this.transitionEnd: true

这个闸一开始默认的状态是开着的,第一次点击以后,这个闸就关上了, this.tranisitonEnd = false ,在再次打开之前,后面的代码都执行不了。接下来就是在恰当的时机把这个闸打开,而这个恰当的时机就是过渡完成时,也就是在 animate函数 里:

animate(des, direc) {  if (this.temp) {     window.clearInterval(this.temp)    this.temp = null   }  this.temp = window.setInterval(() => {    if ((direc === -1 && des  this.distance)) {     this.distance += 30 * direc     } else {     this.transitionEnd = true   //闸再次打开     window.clearInterval(this.temp)     this.distance = des     if (des  -600) this.distance = -3000    }  }, 20)}

登录后复制

这下快速点击就没有之前的那个问题了:

Vue如何制作图片轮播组件(附代码) 

五、点击小圆点实现图片过渡切换

到目前为止的代码:

 

  • Vue如何制作图片轮播组件(附代码)
  • Vue如何制作图片轮播组件(附代码)
  • Vue如何制作图片轮播组件(附代码)

export default { name: 'slider', data () { return { sliders:[ { img:'../../static/images/1.jpg' }, { img:'../../static/images/2.jpg' }, { img:'../../static/images/3.jpg' }, { img:'../../static/images/4.jpg' }, { img:'../../static/images/5.jpg' } ], currentIndex:1, distance:-600, transitionEnd: true } }, computed:{ containerStyle() { return { transform:`translate3d(${this.distance}px, 0, 0)` } } }, methods:{ move(offset, direction) { if (!this.transitionEnd) return this.transitionEnd = false direction === -1 ? this.currentIndex++ : this.currentIndex-- if (this.currentIndex > 5) this.currentIndex = 1 if (this.currentIndex { if ((direc === -1 && des this.distance)) { this.distance += 30 * direc } else { this.transitionEnd = true window.clearInterval(this.temp) this.distance = des if (des -600) this.distance = -3000 } }, 20) } }}

登录后复制

接下来我们要实现点击下面的小圆点来实现过渡和图片切换。

登录后复制

在点击小圆点的时候我们调用 jump 函数,并将索引 i+1 传给它。 这里需要特别注意,小圆点的索引和图片对应的索引不一致,图片共7张,而5个小圆点对应的是图片中中间的5张,所以我们才传 i+1 。

jump(index) {  const direction = index - this.currentIndex >= 0 ? -1 : 1 //获取滑动方向   const offset = Math.abs(index - this.currentIndex) * 600  //获取滑动距离  this.move(offset, direction)}

登录后复制

上面的代码有一个问题,在jump函数里调用move方法,move里对于currentIndex的都是 +1 ,而点击小圆点可能是将 currentIndex 加或者减好多个,所以要对move里的代码修改下:

direction === -1 ? this.currentIndex += offset/600 : this.currentIndex -= offset/600

登录后复制

改一行,根据offset算出currentIndex就行了。

但是又有一个问题,长距离切换速度太慢,如下:

Vue如何制作图片轮播组件(附代码) 

所以我们需要控制一下速度,让滑动一张图片耗费的时间和滑动多张图片耗费的时间一样,给move和animate函数添加一个speed参数,还要再算一下:

jump(index) {  const direction = index - this.currentIndex >= 0 ? -1 : 1  const offset = Math.abs(index - this.currentIndex) * 600  const jumpSpeed = Math.abs(index - this.currentIndex) === 0 ? this.speed : Math.abs(index - this.currentIndex) * this.speed   this.move(offset, direction, jumpSpeed)}

登录后复制

六、自动播放与暂停

前面的写的差不多了,到这里就非常简单了,写一个函数play:

play() {  if (this.timer) {    window.clearInterval(this.timer)    this.timer = null  }  this.timer = window.setInterval(() => {    this.move(600, -1, this.speed)  }, 4000)}

登录后复制

除了初始化以后自动播放,还要通过mouseover和mouseleave来控制暂停与播放:

stop() {  window.clearInterval(this.timer)  this.timer = null}

登录后复制

七、 两处小坑

1. window.onblur 和 window.onfocus

写到这里,基本功能都差不多了。但是如果把页面切换到别的页面,导致轮播图所在页面失焦,过一段时间再切回来会发现轮播狂转。原因是页面失焦以后,setInterval停止运行,但是如果切回来就会一次性把该走的一次性走完。解决的方法也很简单,当页面失焦时停止轮播,页面聚焦时开始轮播。

window.onblur = function() { this.stop() }.bind(this)window.onfocus = function() { this.play() }.bind(this)

登录后复制

2. window.setInterval() 小坑

当定时器 window.setInterval() 在多个异步回调中使用时,就有可能在某种机率下开启多个执行队列, 所以为了保险起见,不仅应该在该清除时清除定时器,还要在每次使用之前也清除一遍 。

八、用props简单写两个对外接口

props: {  initialSpeed: {   type: Number,   default: 30  },  initialInterval: {   type: Number,   default: 4  }},data() {  ......  speed: this.initialSpeed  },computed:{  interval() {    return this.initialInterval * 1000  }}

登录后复制

然后再在相应的地方修改下就可以了。

完整的代码如下:

 

  • Vue如何制作图片轮播组件(附代码)
  • Vue如何制作图片轮播组件(附代码)
  • Vue如何制作图片轮播组件(附代码)

export default { name: 'slider', props: { initialSpeed: { type: Number, default: 30 }, initialInterval: { type: Number, default: 4 } }, data () { return { sliders:[ { img:'../../static/images/1.jpg' }, { img:'../../static/images/2.jpg' }, { img:'../../static/images/3.jpg' }, { img:'../../static/images/4.jpg' }, { img:'../../static/images/5.jpg' } ], currentIndex:1, distance:-600, transitionEnd: true, speed: this.initialSpeed } }, computed:{ containerStyle() { return { transform:`translate3d(${this.distance}px, 0, 0)` } }, interval() { return this.initialInterval * 1000 } }, mounted() { this.init() }, methods:{ init() { this.play() window.onblur = function() { this.stop() }.bind(this) window.onfocus = function() { this.play() }.bind(this) }, move(offset, direction, speed) { if (!this.transitionEnd) return this.transitionEnd = false direction === -1 ? this.currentIndex += offset/600 : this.currentIndex -= offset/600 if (this.currentIndex > 5) this.currentIndex = 1 if (this.currentIndex { if ((direc === -1 && des this.distance)) { this.distance += speed * direc } else { this.transitionEnd = true window.clearInterval(this.temp) this.distance = des if (des -600) this.distance = -3000 } }, 20) }, jump(index) { const direction = index - this.currentIndex >= 0 ? -1 : 1 const offset = Math.abs(index - this.currentIndex) * 600 const jumpSpeed = Math.abs(index - this.currentIndex) === 0 ? this.speed : Math.abs(index - this.currentIndex) * this.speed this.move(offset, direction, jumpSpeed) }, play() { if (this.timer) { window.clearInterval(this.timer) this.timer = null } this.timer = window.setInterval(() => { this.move(600, -1, this.speed) }, this.interval) }, stop() { window.clearInterval(this.timer) this.timer = null } }}

登录后复制

相信看了本文案例你已经掌握了方法,更多精彩请关注【创想鸟】其它相关文章!

推荐阅读:

Bootstrap中使用WebUploader步骤详解

vuex使用步骤剖析

以上就是Vue如何制作图片轮播组件(附代码)的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2764643.html

(0)
上一篇 2025年3月8日 10:33:43
下一篇 2025年3月8日 10:34:12

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • vue地区选择组件教程详解

    这篇文章主要介绍了vue地区选择组件主要用于全国地区数据的操作,包括省,市,区三级联动,地区数据的添加和删除,本文重点给大家介绍vue地区选择组件教程详解,需要的朋友参考下吧 概述 主要用于全国地区数据的操作,包括省,市,区三级联动,地区数…

    编程技术 2025年3月8日
    200
  • React为 Vue 引入容器组件和展示组件的教程详解

    这篇文章主要介绍了react为 vue 引入容器组件和展示组件的教程详解,文中很详细的给大家介绍了使用容器组件的原因,需要的朋友可以参考下 如果你使用过 Redux 开发 React,你一定听过 容器组件(Smart/Container C…

    2025年3月8日
    200
  • vue的组件基础

    本篇文章给大家总结了vue组件基础的相关知识点以及代码实例,有需要的朋友可以学习参考下。 什么是组件 组件(Component)是对数据和方法的简单封装。web中的组件其实可以看成是页面的一个组成部分,它是一个具有独立的逻辑和功能的界面,同…

    2025年3月8日
    200
  • 通用无限极下拉菜单的实现代码

    这篇文章主要介绍了关于通用无限极下拉菜单的实现代码,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 下拉菜单在我开发中经常遇到,但是没个项目都需要从新编写,改起来虽然简单但是很麻烦,我这个人还是比较懒的,今天有时间把我以前的项…

    编程技术 2025年3月8日
    200
  • Vue表单类的父子组件数据传递示例

    这篇文章主要介绍了关于vue表单类的父子组件数据传递示例,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 使用Vue.js进行项目开发,那必然会使用基于组件的开发方式,这种方式的确给开发和维护带来的一定的便利性,但如果涉及到组…

    编程技术 2025年3月8日
    200
  • JS弹出窗口代码大全

    这篇文章主要介绍了关于js弹出窗口代码大全,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 如何利用网页弹出各种形式的窗口,我想大家大多都是知道些的,但那种多种多样的弹出式窗口是怎么搞出来的,平时利用业余时间整理了一些,需要的…

    编程技术 2025年3月8日
    200
  • diff算法使用详解(附代码)

    这次给大家带来diff算法使用详解(附代码),diff算法使用的注意事项有哪些,下面就是实战案例,一起来看一下。 虚拟dom diff算法首先要明确一个概念就是diff的对象是虚拟dom,更新真实dom则是diff算法的结果 Vnode基类…

    编程技术 2025年3月8日
    200
  • vue文件树组件使用技巧

    这次给大家带来vue文件树组件使用技巧,vue文件树组件使用的注意事项有哪些,下面就是实战案例,一起来看一下。 本文主要是分析vue官方仓库里的文件树组件[vue github] demo可以查看 https://codepen.io/sh…

    编程技术 2025年3月8日
    200
  • vue全局与局部组件使用技巧

    这次给大家带来vue全局与局部组件使用技巧,vue全局与局部组件使用的注意事项有哪些,下面就是实战案例,一起来看一下。 main.js入口文件的一些常用配置, 在入口文件上定义的public.vue为全局组件,在这里用的是pug模版 .wr…

    编程技术 2025年3月8日
    200
  • JS实现文件拖拽步骤详解(附代码)

    这次给大家带来JS实现文件拖拽步骤详解(附代码),JS实现文件拖拽的注意事项有哪些,下面就是实战案例,一起来看一下。 1.效果图: 2.源码 #p1 { width: 350px; height: 70px; padding: 10px; …

    2025年3月8日
    200

发表回复

登录后才能评论