当前位置:   article > 正文

Vue2走马灯(Carousel)_vue 走马灯

vue 走马灯

Vue2走马灯扩展版(Carousel)

移入时暂停,移出后自动轮播

可自定义设置以下属性:

  • 轮播图片数组(imageData),默认[]
  • 滑动轮播间隔(interval),默认3000ms
  • 图片宽度(imageWidth),默认400px
  • 图片高度(imageHeight),默认300px

共使用两种滑动效果实现方式:

  • 延时调用setInterval(setTimeout类似)
  • requestAnimationFrame()(效果更好)

效果如下图:

①创建图片轮播组件Carousel.vue:

  • 滑动效果使用setInterval延时调用(使用setTimeout超时调用类似)
  1. <template>
  2. <!-- 方法1:使用 will-change: transform; translateX(-${left}px); -->
  3. <!-- <div class="m-slider" :style="`width: ${imageWidth}px;`" @mouseenter="onStop" @mouseleave="onStart">
  4. <div :class="{ 'transition': transition }" :style="`width: ${width}px; will-change: transform; transform: translateX(${-left}px);`"> -->
  5. <!-- 方法2:使用position: relative;和position: absolute; left: ${-left}px; -->
  6. <div class="m-slider" :style="`position: relative; width: ${imageWidth}px; height: ${imageHeight + 36}px;`" @mouseenter="onStop" @mouseleave="onStart">
  7. <div :class="{ 'transition': transition }" :style="`width: ${width}px; position: absolute; left: ${-left}px;`">
  8. <div
  9. v-for="(item, index) in imageData"
  10. :key="index"
  11. :style="`width: ${imageWidth}px;`"
  12. class="m-image">
  13. <img v-lazy="getDefault(item.imgUrl)" :alt="item.title" :style="`width: ${imageWidth}px; height: ${imageHeight}px;`" class="u-img"/>
  14. <p class="u-img-title" :title="item.title">{{ item.title }}</p>
  15. </div>
  16. <div class="m-image" :style="`width: ${imageWidth}px;`">
  17. <img v-lazy="getDefault(imageData[0].imgUrl)" :alt="imageData[0].title" :style="`width: ${imageWidth}px; height: ${imageHeight}px;`" class="u-img"/>
  18. <p class="u-img-title" :title="imageData[0].title">{{ imageData[0].title }}</p>
  19. </div>
  20. </div>
  21. </div>
  22. </template>
  23. <script>
  24. import Vue from 'vue'
  25. import VueLazyLoad from 'vue-lazyload' // 图片懒加载插件使用版本v1.3.3
  26. Vue.use(VueLazyLoad)
  27. export default {
  28. name: 'Carousel',
  29. props: {
  30. imageData: { // 轮播图片数组
  31. type: Array,
  32. default: () => {
  33. return []
  34. }
  35. },
  36. interval: { // 滑动轮播间隔
  37. type: Number,
  38. default: 3000
  39. },
  40. imageWidth: { // 图片宽度
  41. type: Number,
  42. default: 400
  43. },
  44. imageHeight: { // 图片高度
  45. type: Number,
  46. default: 300
  47. }
  48. },
  49. data () {
  50. return {
  51. left: 0, // 滑动偏移值
  52. transition: false, // 暂停时未完成滑动的过渡标志
  53. slideTimer: null, // 自动切换定时器
  54. moveTimer: null // 向左滑动定时器
  55. }
  56. },
  57. computed: {
  58. width () { // 容器宽度:(图片数组长度+1) * 图片宽度
  59. return (this.imageData.length + 1) * this.imageWidth
  60. },
  61. len () {
  62. return this.imageData.length || 0
  63. }
  64. },
  65. mounted () {
  66. window.onfocus = () => { // 页面激活状态
  67. this.onStart()
  68. }
  69. window.onblur = () => { // 页面未激活状态
  70. this.onStop()
  71. }
  72. this.onStart()
  73. },
  74. methods: {
  75. getDefault (src) { // 获取懒加载默认图
  76. return {
  77. src: src,
  78. error: require('../assets/images/default.png'),
  79. loading: require('../assets/images/default.png')
  80. }
  81. },
  82. onStart () {
  83. if (this.len > 1) { // 超过一条时滑动
  84. this.transition = false
  85. this.onAutoSlide() // 自动滑动轮播
  86. console.log('imageSlider start')
  87. }
  88. },
  89. onStop () {
  90. clearTimeout(this.slideTimer)
  91. clearInterval(this.moveTimer)
  92. this.sliderTimer = null
  93. this.moveTimer = null
  94. this.transition = true
  95. this.left = Math.ceil(this.left / this.imageWidth) * this.imageWidth // ceil:向上取整,floor:向下取整
  96. console.log('imageSlider stop')
  97. },
  98. onAutoSlide () {
  99. this.slideTimer = setTimeout(() => {
  100. const target = this.left % (this.len * this.imageWidth) + this.imageWidth
  101. this.autoMoveLeft(target)
  102. }, this.interval)
  103. },
  104. // 滑动使用setInterval延时调用
  105. autoMoveLeft (target) { // 自动切换,向左滑动效果
  106. if (this.left === this.len * this.imageWidth) { // 最后一张时,重置left
  107. this.left = 0
  108. }
  109. this.moveTimer = setInterval(() => {
  110. if (this.left >= target) {
  111. clearInterval(this.moveTimer)
  112. this.moveTimer = null
  113. this.onAutoSlide() // 自动间隔切换下一张
  114. } else {
  115. var step = Math.ceil((target - this.left) / 10) // 越来越慢的滑动过程
  116. this.left += step
  117. }
  118. }, 25)
  119. },
  120. beforeDestroy () {
  121. clearTimeout(this.slideTimer)
  122. clearInterval(this.moveTimer)
  123. this.slideTimer = null
  124. this.moveTimer = null
  125. }
  126. }
  127. }
  128. </script>
  129. <style lang="less" scoped>
  130. @themeColor: #1890FF;
  131. .m-slider {
  132. margin: 0 auto;
  133. overflow: hidden;
  134. .transition {
  135. transition: transform 0.3s ease-out;
  136. }
  137. .m-image {
  138. display: inline-block;
  139. .u-img {
  140. vertical-align: bottom; // 消除img标签底部的5px
  141. cursor: pointer;
  142. }
  143. .u-img-title {
  144. font-size: 18px;
  145. color: #333;
  146. line-height: 36px;
  147. text-align: left;
  148. cursor: pointer;
  149. overflow: hidden;
  150. text-overflow: ellipsis;
  151. white-space: nowrap;
  152. &:hover {
  153. color: @themeColor;
  154. }
  155. }
  156. }
  157. }
  158. </style>

  • 滑动效果使用requestAnimationFrame()
    1. <template>
    2. <div class="m-slider" :style="`width: ${imageWidth}px;`" @mouseenter="onStop" @mouseleave="onStart">
    3. <div :class="{ 'transition': transition }" :style="`width: ${width}px; will-change: transform; transform: translateX(${-left}px);`">
    4. <div
    5. v-for="(item, index) in imageData"
    6. :key="index"
    7. :style="`width: ${imageWidth}px;`"
    8. class="m-image">
    9. <img v-lazy="getDefault(item.imgUrl)" :alt="item.title" :style="`width: ${imageWidth}px; height: ${imageHeight}px;`" class="u-img"/>
    10. <p class="u-img-title" :title="item.title">{{ item.title }}</p>
    11. </div>
    12. <div class="m-image" :style="`width: ${imageWidth}px;`">
    13. <img v-lazy="getDefault(imageData[0].imgUrl)" :alt="imageData[0].title" :style="`width: ${imageWidth}px; height: ${imageHeight}px;`" class="u-img"/>
    14. <p class="u-img-title" :title="imageData[0].title">{{ imageData[0].title }}</p>
    15. </div>
    16. </div>
    17. </div>
    18. </template>
    19. <script>
    20. import Vue from 'vue'
    21. import VueLazyLoad from 'vue-lazyload'
    22. Vue.use(VueLazyLoad) // 图片懒加载插件
    23. export default {
    24. name: 'Carousel',
    25. props: {
    26. imageData: { // 轮播图片数组
    27. type: Array,
    28. default: () => {
    29. return []
    30. }
    31. },
    32. interval: { // 滑动轮播间隔
    33. type: Number,
    34. default: 3000
    35. },
    36. imageWidth: { // 图片宽度
    37. type: Number,
    38. default: 400
    39. },
    40. imageHeight: { // 图片高度
    41. type: Number,
    42. default: 300
    43. }
    44. },
    45. data () {
    46. return {
    47. left: 0, // 滑动偏移值
    48. transition: false, // 暂停时未完成滑动的过渡标志
    49. slideTimer: null, // 自动切换定时器
    50. moveRaf: null, // 动画回调标识
    51. target: null, // 要移动到的目标位置
    52. start: 0,
    53. end: 0,
    54. fpsRaf: null, // fps回调标识
    55. step: 15 // 默认移动参数,对应60fps
    56. }
    57. },
    58. computed: {
    59. width () { // 容器宽度:(图片数组长度+1) * 图片宽度
    60. return (this.imageData.length + 1) * this.imageWidth
    61. },
    62. len () {
    63. return this.imageData.length || 0
    64. }
    65. },
    66. mounted () {
    67. window.onfocus = () => { // 页面激活状态
    68. this.onStart()
    69. }
    70. window.onblur = () => { // 页面未激活状态
    71. this.onStop()
    72. }
    73. this.fpsRaf = requestAnimationFrame(this.getFPS) // 获取浏览器的刷新率
    74. },
    75. methods: {
    76. getDefault (src) { // 获取懒加载默认图
    77. return {
    78. src: src,
    79. error: require('../assets/images/default.png'),
    80. loading: require('../assets/images/default.png')
    81. }
    82. },
    83. getFPS (timestamp) {
    84. // 单位ms,用1000ms/两个时间的间隔≈刷新频率fps
    85. // console.log('timestamp:', timestamp)
    86. if (this.fpsRaf === 2) {
    87. this.start = timestamp
    88. }
    89. if (this.fpsRaf === 3) {
    90. this.end = timestamp
    91. const fps = Math.floor(1000 / (this.end - this.start))
    92. if (fps === 120) {
    93. this.step = 30
    94. }
    95. }
    96. this.fpsRaf = requestAnimationFrame(this.getFPS)
    97. if (this.fpsRaf > 3) {
    98. cancelAnimationFrame(this.fpsRaf)
    99. this.onStart()
    100. }
    101. },
    102. onStart () {
    103. if (this.len > 1) { // 超过一条时滑动
    104. this.transition = false
    105. this.onAutoSlide() // 自动滑动轮播
    106. console.log('imageSlider start')
    107. }
    108. },
    109. onStop () {
    110. clearTimeout(this.slideTimer)
    111. this.slideTimer = null
    112. cancelAnimationFrame(this.moveRaf)
    113. this.transition = true
    114. this.left = Math.ceil(this.left / this.imageWidth) * this.imageWidth // ceil:向上取整,floor:向下取整
    115. console.log('imageSlider stop')
    116. },
    117. onAutoSlide () {
    118. this.slideTimer = setTimeout(() => {
    119. const target = this.left % (this.len * this.imageWidth) + this.imageWidth
    120. this.autoMoveLeft(target)
    121. }, this.interval)
    122. },
    123. // 滑动效果使用requestAnimationFrame
    124. autoMoveLeft (target) { // 自动切换,向左滑动效果
    125. if (this.left === this.len * this.imageWidth) { // 最后一张时,重置left
    126. this.left = 0
    127. }
    128. this.target = target
    129. this.moveRaf = requestAnimationFrame(this.autoLeftSlideEffect)
    130. },
    131. autoLeftSlideEffect () { // 自动向左滑动效果
    132. if (this.left >= this.target) {
    133. cancelAnimationFrame(this.moveRaf)
    134. this.onAutoSlide() // 自动间隔切换下一张
    135. } else {
    136. const move = Math.ceil((this.target - this.left) / this.step)
    137. this.left += move
    138. this.moveRaf = requestAnimationFrame(this.autoLeftSlideEffect)
    139. }
    140. },
    141. beforeDestroy () {
    142. clearTimeout(this.slideTimer)
    143. this.slideTimer = null
    144. }
    145. }
    146. }
    147. </script>
    148. <style lang="less" scoped>
    149. @themeColor: #1890FF;
    150. .m-slider {
    151. margin: 100px auto;
    152. overflow: hidden;
    153. .transition {
    154. transition: transform 0.3s ease-out;
    155. }
    156. .m-image {
    157. display: inline-block;
    158. .u-img {
    159. vertical-align: bottom; // 消除img标签底部的5px
    160. cursor: pointer;
    161. }
    162. .u-img-title {
    163. font-size: 18px;
    164. color: #333;
    165. line-height: 36px;
    166. text-align: left;
    167. cursor: pointer;
    168. overflow: hidden;
    169. text-overflow: ellipsis;
    170. white-space: nowrap;
    171. &:hover {
    172. color: @themeColor;
    173. }
    174. }
    175. }
    176. }
    177. </style>

    ②在要使用滑动轮播图片的页面引入使用:

    1. <Carousel :imageData="imageData" :imageWidth="460" :imageHeight="320" :interval="3000" />
    2. import Carousel from '@/components/Carousel'
    3. components: {
    4. Carousel
    5. }
    6. data () {
    7. return {
    8. imageData: [
    9. {
    10. title: 'image-1,image-1,image-1,image-1,image-1,image-1,image-1,image-1,image-1',
    11. imgUrl: 'image src...'
    12. },
    13. {
    14. title: 'image-2,image-2,image-2,image-2,image-2,image-2,image-2,image-2,image-2',
    15. imgUrl: 'image src...'
    16. },
    17. {
    18. title: 'image-3,image-3,image-3,image-3,image-3,image-3,image-3,image-3,image-3',
    19. imgUrl: 'image src...'
    20. }
    21. ]
    22. }
    23. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/250945
推荐阅读
相关标签
  

闽ICP备14008679号