基于Vue3实现鼠标滑动和滚轮控制的轮播

 更新时间:2024年02月29日 14:05:54   作者:Jiude  
在这篇文章主要为大家详细介绍了如何一步步地实现一个基于 Vue 3 的轮播组件,这个组件的特点是可以通过鼠标滑动和滚轮来控制轮播图的切换,感兴趣的可以了解下

需求

实现一个轮播组件,这个组件应该有以下的特性:

  • 用户可以通过鼠标点击来切换轮播图。
  • 用户可以通过鼠标滑动来切换轮播图。
  • 用户可以通过鼠标滚轮来切换轮播图。
  • 一开始自动切换,用户操作时停止自动切换,用户停止操作一段时间后,继续自动切换。

效果图

分析与设计

数组结构:

interface ListType {
    title: string
    icon: string
    img: string
    desc: string[]
}
const list: ListType = []

轮播中有一个唯一的active项,设置其下标为activeIndex

<ul class="swipper-wrapper">
    <li class="swipper-item" 
        v-for="(item, index) in list" 
        :class="{ active: index === activeIndex }"
        @click="activeIndex = index"
     >
      <img class="swipper-item-icon" :src="item.icon" alt="">
      {{ item.title }}
    </li>
 </ul>
const activeIndex = ref(0)

轮播最多可以同时展示7项,设置常量NUM默认值为7,理论上来说可以通过activeIndex获取展示的这7项的下标(即取距离activeIndex最近的7项, 因为需要距离最近,所以暂定这里NUM为奇数):

const NUM = 7 // 展示的卡片数量(奇数)
function getSurroundingNumbers(length: number, activeIndex: number) {
  var start = activeIndex - (NUM - 1) / 2;
  var end = activeIndex + (NUM + 1) / 2;

  if (activeIndex < (NUM - 1) / 2) {
    start = 0;
    end = NUM;
  }

  if (activeIndex > length - (NUM + 1) / 2) {
    start = length - NUM;
    end = length;
  }

  var result = [];
  for (var i = start; i < end; i++) {
    result.push(i);
  }

  return result;
}

const surroundingNumbers = computed(() => getSurroundingNumbers(list.length, activeIndex.value))

比较每一项的下标和surroundingNumbers,知道他在数组的前面还是后面还是里面,从而设置相应的样式:

function getSwiperItemStyle(index: number) {
  // 每个卡片高度60px 间隔16px
  // 最多正常展示NUM个,其余藏在后,只露出16px高度
  const HIDEH = 15,
    H = 60,
    M = 16;
  
  let y = 0,
    scaleX = 1,
    backgroundColor = '#f9fbfc',
    zIndex = 9999,
    boxShadow = '2px 2px 1px 0px rgba(0,0,0,0.04), #fff 0px -2px 0px 0px';

  if (!surroundingNumbers.value.includes(index)) {
    backgroundColor = '#EBEDF2'
    zIndex = zIndex - Math.abs(activeIndex.value - index) + 2
    scaleX = 0.98 ** (Math.abs(activeIndex.value - index) + 2)

    if (index < surroundingNumbers.value[0]) {
      // 在上面
      y = HIDEH * index
      scaleX = 0.98 ** (surroundingNumbers.value[0] - index)
      boxShadow = '2px 2px 1px 0px rgba(255, 255, 255, .3) inset';
    } else {
      // 在下面
      y = surroundingNumbers.value[0] * HIDEH + (NUM - 1) * (H + M) + (index - surroundingNumbers.value.at(-1)!) * HIDEH
      scaleX = 0.98 ** (index - surroundingNumbers.value.at(-1)!)
      boxShadow = '2px 2px 1px 0px rgba(0,0,0,0.04)';
    }
  } else {
    y = surroundingNumbers.value[0] * HIDEH + (index - surroundingNumbers.value[0]) * (H + M)
  }

  if (activeIndex.value === index) {
    boxShadow = '5px 6px 12px 0px rgba(0,0,0,0.08), #fff 0px -2px 0px 0px';
  }


  return {
    transform: 'translateY(' + y / 19.2 + 'vw) scaleX(' + scaleX + ')',
    backgroundColor,
    zIndex,
    boxShadow
  }
}
<ul class="swipper-wrapper">
    <li class="swipper-item" 
        v-for="(item, index) in list" 
        :class="{ active: index === activeIndex }"
        :style="getSwiperItemStyle(index)"
        @click="activeIndex = index"
     >
      <img class="swipper-item-icon" :src="item.icon" alt="">
      {{ item.title }}
    </li>
 </ul>

交互实现

鼠标滚轮切换

绑定滚动事件@wheel="wheel"

// 处理鼠标滚动
function wheel(event: WheelEvent) {
  event.preventDefault(); // 防止页面滚动
  if (event.deltaY < 0) {
    // 向下滚动,activeIndex减少
    activeIndex.value = Math.max(0, activeIndex.value - 1);
  } else {
    // 向上滚动,activeIndex增加
    activeIndex.value = Math.min(list.length - 1, activeIndex.value + 1);
  }
}

鼠标滑动切换

绑定鼠标事件@mousedown="startSwipe" @mousemove="swipe" @mouseup="endSwipe" @mouseleave="endSwipe"

// 处理滑动
let startY = 0; // 鼠标按下时的y坐标
let accumulatedDiffY = 0; // 累积的滑动距离
let swiping = false; // 是否正在滑动

function startSwipe(event: MouseEvent) {
  startY = event.clientY;
  swiping = true;
}

function swipe(event: MouseEvent) {
  if (!swiping) return;
  const currentY = event.clientY;
  const diffY = currentY - startY;

  // 累积滑动距离
  accumulatedDiffY += diffY;

  // 假设每个元素的高度是100px
  const elementHeight = 84;

  // 使用累积的滑动距离计算滑动的元素数量,向下取整
  const numItems = Math.floor(Math.abs(accumulatedDiffY) / elementHeight);

  if (accumulatedDiffY > 0) {
    // 向下滑动,activeIndex减少
    if (activeIndex.value <= 2) return
    activeIndex.value = Math.min(list.length - 3, activeIndex.value)
    activeIndex.value = Math.max(0, activeIndex.value - numItems);
    accumulatedDiffY -= numItems * elementHeight; // 更新累积的滑动距离
  } else {
    // 向上滑动,activeIndex增加
    if (activeIndex.value >= list.length - 3) return
    activeIndex.value = Math.max(2, activeIndex.value)
    activeIndex.value = Math.min(list.length - 1, activeIndex.value + numItems);
    accumulatedDiffY += numItems * elementHeight; // 更新累积的滑动距离
  }

  // 更新起始Y坐标
  startY = currentY;
}

function endSwipe(event: MouseEvent) {
  swiping = false;
  accumulatedDiffY = 0; // 结束滑动时重置累积的滑动距离
}

自动切换

// 自动切换定时器
const { pause, resume } = useIntervalFn(() => {
  activeIndex.value++
  if (activeIndex.value >= list.length - 1) {
    activeIndex.value = 0
  }
}, 3000)

// 重新自动切换的倒计时
const { start: startTimeoutFn, stop: stopTimeoutFn } = useTimeoutFn(resume, 5000)

在每个用户操作的方法里先暂停自动切换pause()并停止继续切换的倒计时stopTimeoutFn,结束操作时再开启继续切换的倒计时startTimeoutFn

完整代码

到此这篇关于基于Vue3实现鼠标滑动和滚轮控制的轮播的文章就介绍到这了,更多相关Vue3轮播内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 加载 vue 远程代码的组件实例详解

    加载 vue 远程代码的组件实例详解

    vue-cli 作为 Vue 官方推荐的项目构建脚手架,它提供了开发过程中常用的,热重载,构建,调试,单元测试,代码检测等功能。我们本次的异步远端组件将基于 vue-cli 开发
    2017-11-11
  • vue-cli脚手架config目录下index.js配置文件的方法

    vue-cli脚手架config目录下index.js配置文件的方法

    下面小编就为大家分享一篇vue-cli脚手架config目录下index.js配置文件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03
  • vue+element ui表格添加多个搜索条件筛选功能(前端查询)

    vue+element ui表格添加多个搜索条件筛选功能(前端查询)

    这篇文章主要给大家介绍了关于vue+element ui表格添加多个搜索条件筛选功能的相关资料,最近在使用element-ui的表格组件时,遇到了搜索框功能的实现问题,需要的朋友可以参考下
    2023-08-08
  • Vue使用Echarts实现大屏可视化布局示例详细讲解

    Vue使用Echarts实现大屏可视化布局示例详细讲解

    这篇文章主要介绍了Vue使用Echarts实现大屏可视化布局示例,本文通过实例代码图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-01-01
  • vue实现视频上传功能

    vue实现视频上传功能

    这篇文章主要为大家详细介绍了vue实现视频上传功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • vue项目部署自动清除缓存方式

    vue项目部署自动清除缓存方式

    这篇文章主要介绍了vue项目部署自动清除缓存方式,包括清除文件缓存,清除浏览器 localStorage 缓存方式,本文结合示例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • Vuex数据的存储与获取方式

    Vuex数据的存储与获取方式

    这篇文章主要介绍了Vuex数据的存储与获取方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • 从0搭建vue-cli4脚手架

    从0搭建vue-cli4脚手架

    这篇文章主要介绍了从0搭建vue-cli4脚手架,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • 应用provide与inject刷新Vue页面方法

    应用provide与inject刷新Vue页面方法

    这篇文章主要介绍了应用provide与inject刷新Vue页面的两种方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,多多进步,祝大家早日升职加薪
    2021-09-09
  • Vue3项目中使用自适应Rem示例

    Vue3项目中使用自适应Rem示例

    这篇文章主要为大家介绍了Vue3项目中使用自适应Rem示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08

最新评论