index.vue 4.96 KB
<template>
  <div 
    @mouseenter="handleMouseenter"
    @mouseleave="handleMouseleave"
   class="banner-box" ref="root">
    <div class="wrapper">
      <div v-for="(item, index) in option.dataset" :key="index + item" :class="item.className" :style="item.sty">
        <CameraItem
          ref="cameraRef"
          :name="item.name"
          :avatar="item.avatar"
          :key="item + index"
          :sourceSrc="item.url"
          :w="w"
          :h="h"
          :index="index"
        />
        <span class="video-title">{{ item.name }}</span>
      </div>
    </div>
    <a v-show="isShowSvg" href="javascript:;" class="left" @click="changeSlide('left')"></a>
    <a v-show="isShowSvg" href="javascript:;" class="right" @click="changeSlide('right')"></a>
  </div>
</template>
<script setup lang="ts" name="index">
import { PropType, watch, toRefs, shallowReactive, onMounted, ref } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import 'video.js/dist/video-js.min.css'
import { option as configOption } from './config'
import { CameraItem } from './components'

const props = defineProps({
  chartConfig: {
    type: Object as PropType<CreateComponentType>,
    required: true
  }
})

const isShowSvg = ref(false)

const { w, h } = toRefs(props.chartConfig.attr)

const option = shallowReactive({
  dataset: configOption.dataset
})

const cameraRef = ref<InstanceType<typeof CameraItem>>()

let initial = ref(0)

let interval = ref(2500)

const computedFunc = (initial: number, source: any) => {
  if (initial < 0) initial = 0
  if (Array.isArray(source)) {
    let len = source.length,
      temp1 = initial - 2 < 0 ? initial - 2 + len : initial - 2,
      temp2 = initial - 1 < 0 ? initial - 1 + len : initial - 1,
      temp3 = initial,
      temp4 = initial + 1 >= len ? initial + 1 - len : initial + 1,
      temp5 = initial + 2 >= len ? initial + 2 - len : initial + 2
    return source?.map((item: any, index: number) => {
      let transform = `translateX(-50%) scale(0.7)`,
        zIndex = 0,
        className = 'slide'
      switch (index) {
        case temp3:
          transform = `translateX(-50%) scale(1)`
          className = ['slide', 'activate'] as any
          zIndex = 300
          break
        case temp1:
          transform = `translateX(-80%) scale(0.7)`
          zIndex = 100
          break
        case temp5:
          transform = `translateX(100%) scale(0.7)`
          zIndex = 100
          break
        case temp2:
          transform = `translateX(-100%) scale(0.85)`
          zIndex = 200
          break
        case temp4:
          transform = `translateX(58%) scale(0.85)`
          zIndex = 200
          break
      }
      item.sty = {
        transform,
        zIndex
      }
      item.className = className
      return item
    })
  }
}

watch(
  () => props.chartConfig.option.dataset,
  newData => {
    option.dataset = newData
  },
  {
    immediate: true,
    deep: true
  }
)

option.dataset = computedFunc(initial.value, option.dataset)

watch(
  () => initial.value,
  newV => {
    option.dataset = computedFunc(newV, option.dataset)
  }
)

// 处理自动轮播
let timer: any = null

const autoPlay = () => {
  timer = setInterval(() => {
    initial.value++
    if (initial.value >= option.dataset.length) {
      initial.value = 0
    }
  }, interval.value)
}

// 鼠标移入移除效果
let root = ref(null)

onMounted(() => {
  clearInterval(timer)
  autoPlay()
  const box: any = root.value
  box.onmouseenter = () => clearInterval(timer)
  box.onmouseleave = () => autoPlay()
})

// 点击左右按钮切换图片
function changeVideo(dir: string) {
  if (dir === 'left') {
    clearInterval(timer)
    initial.value++
    initial.value >= option.dataset.length ? (initial.value = 0) : false
    return
  }
  initial.value--
  initial.value < 0 ? (initial.value = option.dataset.length - 1) : false
}

// 左右切换图片设置防抖效果
function changeSlide(dir: string) {
  changeVideo(dir)
}

const handleMouseenter = () => {
  isShowSvg.value = true
}

const handleMouseleave = () => (isShowSvg.value = false)
</script>

<style lang="scss" scoped>
.banner-box {
  .wrapper {
    height: 100%;
    display: flex;
    overflow: hidden;
    .slide {
      width: 20%;
      height: 100%;
      position: absolute;
      left: 10%;
      transform: translateX(-50%);
      transition: 0.5s;
      box-shadow: 0 0 4px black;
      .video-title {
        width: v-bind('w+"px"');
        font-size: 30px;
        color: white;
        position: absolute;
        bottom: 6%;
        left: 10%;
        z-index: 999;
      }
    }
  }
  .arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 90000000;
    width: 50px;
    height: 50px;
    background-size: contain;
    background-color: white;
    opacity: 0.5;
  }
  a.left {
    @extend .arrow;
    background-image: url('./static/left.svg');
    left: 0px;
  }
  a.right {
    @extend .arrow;
    background-image: url('./static/right.svg');
    right: 0px;
  }
}
</style>