For the record - are you still using traditional carousel components? Let's take a look at the mask carousel component

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 definePropsdefines a series of properties through , and uses to refcreate some responsive variables, such as currentIndex, oldCurrentIndex, imgList, and zIndexArrso on.

In onMountedthe hook function, we set a timer to execute the carousel animation every once in a while. In the template part, we use a v-forcommand 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…

This article is reproduced in:

https://juejin.cn/post/7251564871510163512

If it is helpful to you, you are welcome to pay attention. I will update the technical documents regularly, and we will discuss and learn together and make progress together.

 

Guess you like

Origin blog.csdn.net/qq_40716795/article/details/131821358