记录–你还在用传统轮播组件吗?来看看遮罩轮播组件

  • 记录–你还在用传统轮播组件吗?来看看遮罩轮播组件已关闭评论
  • 96 次浏览
  • A+
所属分类:Web前端
摘要

最近有一个页面改版的需求,在UI走查阶段,设计师说原来的轮播组件和新版页面UI整体风格不搭,所以要换掉。


这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--你还在用传统轮播组件吗?来看看遮罩轮播组件

 

背景

最近有一个页面改版的需求,在UI走查阶段,设计师说原来的轮播组件和新版页面UI整体风格不搭,所以要换掉。

这里就涉及到两种轮播组件,一种是传统的轮播组件,一种是设计师要的那种。

传统的轮播组件,大家都见过,原理也清楚,就是把要轮播的图片横向排成一个队列,把他们当成一个整体,每次轮换,其实是把这个队列整体往左平移X像素,这里的X通常就是一个图片的宽度。 这种效果可以参见vant组件库里的swipe组件

而我们设计师要的轮播效果是另外一种,因为我利用端午假期已经做好了一个雏形,所以大家可以直接看Demo

当然你也可以直接打开 腾讯视频APP 首页,顶部的轮播,就是我们设计师要的效果。

需求分析

新式轮播,涉及要两个知识点:

  • 图片层叠
  • 揭开效果

与传统轮播效果一个最明显的不同是,新的轮播效果需要把N张待轮播的图片在Z轴上重叠放置,每次揭开其中的一张,下一张是自然漏出来的。这里的实现方式也有多种,但最先想到的还是用zindex的方案。

第二个问题是如何实现揭开的效果。这里就要使用到css3的新属性mask。 mask是一系列css的简化属性。包括mask-image, mask-position等。 因为mask的系列属性还有一定的兼容性,所以一部分浏览器需要带上-webkit-前缀才能生效。

还有少数浏览器不支持mask属性,退化的情况是轮播必须有效,但是没有轮换的动效。

实现

有了以上的分析,就可以把效果做出来了。核心代码如下:

<script setup lang="ts">  import { ref, onMounted, watch } from "vue";  // 定义属性 const props = defineProps([   'imgList',   'duration',    'transitionDuration',   'maskPositionFrom',    'maskPositionTo',   'maskImageUrl' ]);  // 定义响应式变量 const currentIndex = ref(0); const oldCurrentIndex = ref(0); const imgList = ref([...props.imgList, props.imgList[0]]); const getInitZindex = () => {   const arr = [1];   for (let i = imgList.value.length - 1; i >= 1; i--) {     arr.unshift(arr[0] + 1);   }   return arr; } const zIndexArr = ref([...getInitZindex()]); const maskPosition = ref(props.maskPositionFrom || 'left'); const transition = ref(`all ${props.transitionDuration || 1}s`);  // 设置动画参数 const transitionDuration = props.transitionDuration || 1000; const duration = props.duration || 3000;   // 监听currentIndex变化 watch(currentIndex, () => {   if (currentIndex.value === 0) {     zIndexArr.value = [...getInitZindex()];   }   maskPosition.value = props.maskPositionFrom || 'left';   transition.value = 'none'; })  // 执行动画 const execAnimation = () => {   transition.value = `all ${props.transitionDuration || 1}s`;   maskPosition.value = props.maskPositionFrom || 'left';   maskPosition.value = props.maskPositionTo || 'right';   oldCurrentIndex.value = (currentIndex.value + 1) % (imgList.value.length - 1);    setTimeout(() => {     zIndexArr.value[currentIndex.value] = 1;     currentIndex.value = (currentIndex.value + 1) % (imgList.value.length - 1);   }, 1000) }  // 挂载时执行动画 onMounted(() => {   const firstDelay = duration - transitionDuration;   function animate() {     execAnimation();     setTimeout(animate, duration);   }   setTimeout(animate, firstDelay); })  </script>  <template>   <div class="fly-swipe-container">     <div class="swipe-item"          :class="{'swipe-item-mask': index === currentIndex}"          v-for="(url, index) in imgList"          :key="index"          :style="{ zIndex: zIndexArr[index],          'transition': index === currentIndex ? transition : 'none',          'mask-image': index === currentIndex ? `url(${maskImageUrl})` : '',          '-webkit-mask-image': index === currentIndex ? `url(${maskImageUrl})`: '',          'mask-position':  index === currentIndex ? maskPosition: '',          '-webkit-mask-position':  index === currentIndex ? maskPosition: '' }">       <img :src="url" alt="">     </div>     <div class="fly-indicator">       <div class="fly-indicator-item"            :class="{'fly-indicator-item-active': index === oldCurrentIndex}"            v-for="(_, index) in imgList.slice(0, imgList.length - 1)"            :key="index"></div>     </div>   </div> </template>  <style lang="less" scoped> .fly-swipe-container {   position: relative;   overflow: hidden;   width: 100%;   height: inherit;    .swipe-item:first-child {     position: relative;   }   .swipe-item {     position: absolute;     width: 100%;     top: 0;     left: 0;      img {       display: block;       width: 100%;       object-fit: cover;     }   }    .swipe-item-mask {     mask-repeat: no-repeat;     -webkit-mask-repeat: no-repeat;     mask-size: cover;     -webkit-mask-size: cover;   }    .fly-indicator {     display: flex;     justify-content: center;     align-items: center;     z-index: 666;     position: relative;     top: -20px;     .fly-indicator-item {       margin: 0 5px;       width: 10px;       height: 10px;       border-radius: 50%;       background: gray;     }     .fly-indicator-item-active {       background: #fff;     }   } } </style>

这是一个使用 Vue 3 构建的图片轮播组件。在这个组件中,我们可以通过传入一组图片列表、切换动画的持续时间、过渡动画的持续时间、遮罩层的起始位置、遮罩层的结束位置以及遮罩层的图片 URL 来自定义轮播效果。

组件首先通过 defineProps 定义了一系列的属性,并使用 ref 创建了一些响应式变量,如 currentIndexoldCurrentIndeximgListzIndexArr 等。

onMounted 钩子函数中,我们设置了一个定时器,用于每隔一段时间执行一次轮播动画。 在模板部分,我们使用了一个 v-for 指令来遍历图片列表,并根据当前图片的索引值为每个图片元素设置相应的样式。同时,我们还为每个图片元素添加了遮罩层,以实现轮播动画的效果。

在样式部分,我们定义了一些基本的样式,如轮播容器的大小、图片元素的位置等。此外,我们还为遮罩层设置了一些样式,包括遮罩图片的 URL、遮罩层的位置等。

总之,这是一个功能丰富的图片轮播组件,可以根据传入的参数自定义轮播效果。

后续

因为mask可以做的效果还有很多,后续该组件可以封装更多轮播效果,比如从多个方向的揭开效果,各种渐变方式揭开效果。欢迎使用和提建议。

仓库地址:github.com/cunzaizhuyi…

本文转载于:

https://juejin.cn/post/7251564871510163512

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--你还在用传统轮播组件吗?来看看遮罩轮播组件