Here I will share with you some of the knowledge I have summarized on the Internet, I hope it will be helpful to everyone
background
Recently, there was a need for a page revision. During the UI walkthrough, the designer said that the original carousel component did not match the overall style of the new page UI, so it had to be replaced.
There are two kinds of carousel components involved here, one is the traditional carousel component, and the other is the one that the designer wants.
Everyone has seen the traditional carousel component, and the principle is clear. It is to arrange the pictures to be rotated horizontally into a queue, and treat them as a whole. Each time the rotation is actually, the entire queue is shifted to the left by X pixels. X here is usually the width of a picture. This effect can be seen in the swipe component in the vant component library
The carousel effect our designers want is another, because I have already made a prototype during the Dragon Boat Festival holiday, so you can watch the demo directly .
Of course, you can also directly open the homepage of Tencent Video APP, the carousel at the top is the effect our designers want.
demand analysis
The new carousel involves two knowledge points:
- picture cascading
- Reveal the effect
One of the most obvious differences from the traditional carousel effect is that the new carousel effect needs to overlap and place N pictures to be rotated on the Z-axis, and each time one of them is uncovered, the next one is naturally leaked out . There are also many ways to achieve this, but the first thing that comes to mind is the solution of using zindex.
The second question is how to achieve the effect of uncovering. Here we will use the new attribute mask of css3. mask is a series of simplified properties of css. Including mask-image, mask-position, etc. Because the mask series attributes still have certain compatibility, some browsers need to bring the -webkit- prefix to take effect.
There are also a few browsers that do not support the mask attribute. The degenerate situation is that the rotation must be effective, but there is no rotation effect.
accomplish
With the above analysis, the effect can be made. The core code is as follows:
<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>
This is an image carousel component built with Vue 3. In this component, we can customize by passing in a list of images, the duration of the transition animation, the duration of the transition animation, the start position of the mask layer, the end position of the mask layer, and the image URL of the mask layer Carousel effect.
The component first defineProps
defines a series of properties through , and uses to ref
create some responsive variables, such as currentIndex
, oldCurrentIndex
, imgList
, and zIndexArr
so on.
In onMounted
the hook function, we set a timer to execute the carousel animation every once in a while. In the template part, we use a v-for
command to traverse the image list, and set the corresponding style for each image element according to the index value of the current image. At the same time, we also added a mask layer to each image element to achieve the effect of carousel animation.
In the style section, we define some basic styles, such as the size of the carousel container, the position of the image element, etc. In addition, we also set some styles for the mask layer, including the URL of the mask image, the position of the mask layer, etc.
In short, this is a feature-rich image carousel component, which can customize the carousel effect according to the parameters passed in.
Follow up
Because there are many effects that the mask can do, this component can encapsulate more carousel effects in the future, such as revealing effects from multiple directions, and revealing effects in various gradient ways. Use and suggestions are welcome.
Warehouse address: github.com/cunzaizhuyi…