Carousel组件

# 原理

直接添加的节点,操作追加dom; 定时移除节点;

# 实现

# 入口

carousel/index.js

import Carousel from './carousel'
import '../../style/carousel.scss'

Carousel.install = (app) => {
    app.component(Carousel.name, Carousel)
}
export default Carousel
1
2
3
4
5
6
7

# 属性封装

carousel-props.js

export default {
    height: {
        type: String, // 200px
        default: "200px",
    },
    autoplay: {
        type: Boolean,
        default: true,
    },
    delay: {
        type: Number,
        default: 3000,
    },
    initialIndex: {
        type: Number,
        default: 0,
    },
    loop: {
        type: Boolean,
        default: true,
    },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

使用

import props from "./carousel-props";
export default {
  // $children
  name: "RCarousel",
  props,
  }
1
2
3
4
5
6

# 设置滚动

  • 控制临界点;
  • 鼠标处理;
  • 自动滚动处理;
  • 底部及切换;
    const methods = {
      handleMouseEnter() {
        clearInterval(timer);
        timer = null;
      },
      handleMouseLeave() {
        methods.run();
      },
      go(newIndex, flag) {
        // 临界条件 到了最后一张的下一张是第一张 第一张的前一张是最后一张
        let index = state.currentSelected;
        if (newIndex == state.len) newIndex = 0;
        if (newIndex == -1) newIndex = state.len - 1;
        // 根据上一次的值和当前值 做一个运算 判断是正向还是反向
        state.reverse = index > newIndex ? true : false;
        // 3 => 0 正   0=》3 反
        if ((timer || flag) && props.loop) {
          // 如果是自动轮播 处理最后的边界条件
          if (index == 0 && newIndex == state.len - 1) {
            state.reverse = true;
          }
          if (index == state.len - 1 && newIndex == 0) {
            state.reverse = false;
          }
        }
        nextTick(() => {
          state.currentSelected = newIndex; // 保证样式的reverse 已经添加到dom上了 在去更新状态
        });
      },
      run() {
        // 默认运行逻辑
        if (props.autoplay) {
          // 是否需要自动轮播
          timer = setInterval(() => {
            let index = state.currentSelected;
            let newIndex = index - 1;
            methods.go(newIndex);
          }, props.delay);
        }
      },
    };
    onMounted(() => {
      state.len = state.currentIndex;
      methods.run();
    });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# item处理

<template>
  <!-- carousel-enter-acitve enter to... -->
  <transition name="carousel">
    <div class="r-carousel-item" v-if="isVisible" :class="classs">
      <slot></slot>
    </div>
  </transition>
</template>
<script>
import { computed, inject } from "vue";
export default {
  name: "RCarouselItem",
  setup() {
    let { state, changeIndex } = inject("current");
    let currentIndex = state.currentIndex; // 这个是插槽对应的索引 carousel-item

    let isVisible = computed(() => {
      // currentSelected 当前要显示哪一个
      return state.currentSelected == currentIndex;
    });

    let classs = computed(() => [state.reverse ? "reverse" : ""]);

    changeIndex();
    return {
      isVisible,
      classs,
    };
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 父子组件通讯

provide("current", { state, changeIndex }); // provide 经常在插件中使用;在子item会用到
1
export default {
  name: "RCarouselItem",
  setup() {
    let { state, changeIndex } = inject("current");
    let currentIndex = state.currentIndex; // 这个是插槽对应的索引 carousel-item

    let isVisible = computed(() => {
      // currentSelected 当前要显示哪一个
      return state.currentSelected == currentIndex;
    });

    let classs = computed(() => [state.reverse ? "reverse" : ""]);

    changeIndex();
    return {
      isVisible,
      classs,
    };
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

单独抽取实现

import CarouselItem from '../carousel/carousel-item'
import '../../style/carousel-item.scss'

CarouselItem.install = (app) => {
    app.component(CarouselItem.name,CarouselItem)
}
export default CarouselItem
1
2
3
4
5
6
7
上次更新: 2022/04/15, 05:41:28
×