背景

最近有一个页面改版的需要,在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能够做的成果还有很多,后续该组件能够封装更多轮播成果,比方从多个方向的揭开成果,各种突变形式揭开成果。欢送应用和提倡议。

仓库地址:https://github.com/cunzaizhuyi/fly-comp