共计 3887 个字符,预计需要花费 10 分钟才能阅读完成。
背景
最近有一个页面改版的需要,在 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
创立了一些响应式变量,如 currentIndex
、oldCurrentIndex
、imgList
、zIndexArr
等。
在 onMounted
钩子函数中,咱们设置了一个定时器,用于每隔一段时间执行一次轮播动画。
在模板局部,咱们应用了一个 v-for
指令来遍历图片列表,并依据以后图片的索引值为每个图片元素设置相应的款式。同时,咱们还为每个图片元素增加了遮罩层,以实现轮播动画的成果。
在款式局部,咱们定义了一些根本的款式,如轮播容器的大小、图片元素的地位等。此外,咱们还为遮罩层设置了一些款式,包含遮罩图片的 URL、遮罩层的地位等。
总之,这是一个功能丰富的图片轮播组件,能够依据传入的参数自定义轮播成果。
后续
因为 mask 能够做的成果还有很多,后续该组件能够封装更多轮播成果,比方从多个方向的揭开成果,各种突变形式揭开成果。欢送应用和提倡议。
仓库地址:https://github.com/cunzaizhuyi/fly-comp