Heim > Web-Frontend > View.js > So verwenden Sie vue3+Pinia+TypeScript, um eine gekapselte Karussellkomponente zu implementieren

So verwenden Sie vue3+Pinia+TypeScript, um eine gekapselte Karussellkomponente zu implementieren

WBOY
Freigeben: 2023-05-30 09:40:06
nach vorne
2066 Leute haben es durchsucht

Warum Kapselung?

  • Entspricht der modularen Entwicklungsidee von es6

  • Registriert als globale Komponente, die besser wiederverwendet werden kann, verwenden Sie einfach Tags direkt

Die statische Struktur kann später geändert werden

<script lang="ts" setup name="XtxCarousel">
defineProps()
</script>
<template>
  <div class="xtx-carousel">
    <ul class="carousel-body">
      <li class="carousel-item fade">
        <RouterLink to="/">
          <img
            src="https://cache.yisu.com/upload/information/20220725/112/220.jpg"
            alt=""
          />
        </RouterLink>
      </li>
      <li class="carousel-item">
        <RouterLink to="/">
          <img
            src="https://cache.yisu.com/upload/information/20220725/112/220.jpg"
            alt=""
          />
        </RouterLink>
      </li>
      <li class="carousel-item">
        <RouterLink to="/">
          <img
            src="https://cache.yisu.com/upload/information/20220725/112/220.jpg"
            alt=""
          />
        </RouterLink>
      </li>
    </ul>
    <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  class="carousel-btn prev"
      ><i class="iconfont icon-angle-left"></i
    ></a>
    <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  class="carousel-btn next"
      ><i class="iconfont icon-angle-right"></i
    ></a>
    <div class="carousel-indicator">
      <span class="active"></span>
      <span></span>
      <span></span>
      <span></span>
      <span></span>
    </div>
  </div>
</template>

<style scoped lang="less">
.xtx-carousel {
  width: 100%;
  height: 100%;
  min-width: 300px;
  min-height: 150px;
  position: relative;
  .carousel {
    &-body {
      width: 100%;
      height: 100%;
    }
    &-item {
      width: 100%;
      height: 100%;
      position: absolute;
      left: 0;
      top: 0;
      opacity: 0;
      transition: opacity 0.5s linear;
      &.fade {
        opacity: 1;
        z-index: 1;
      }
      img {
        width: 100%;
        height: 100%;
      }
    }
    &-indicator {
      position: absolute;
      left: 0;
      bottom: 20px;
      z-index: 2;
      width: 100%;
      text-align: center;
      span {
        display: inline-block;
        width: 12px;
        height: 12px;
        background: rgba(0, 0, 0, 0.2);
        border-radius: 50%;
        cursor: pointer;
        ~ span {
          margin-left: 12px;
        }
        &.active {
          background: #fff;
        }
      }
    }
    &-btn {
      width: 44px;
      height: 44px;
      background: rgba(0, 0, 0, 0.2);
      color: #fff;
      border-radius: 50%;
      position: absolute;
      top: 228px;
      z-index: 2;
      text-align: center;
      line-height: 44px;
      opacity: 0;
      transition: all 0.5s;
      &.prev {
        left: 20px;
      }
      &.next {
        right: 20px;
      }
    }
  }
  &:hover {
    .carousel-btn {
      opacity: 1;
    }
  }
}
</style>
Nach dem Login kopieren

Anforderungsdaten werden in Pinia gespeichert

import { defineStore } from &#39;pinia&#39;
import request from &#39;@/utils/request&#39;
import { BannerItem, IApiRes } from &#39;@/types/data&#39;

export default defineStore(&#39;home&#39;, {
  persist: {
    enabled: true
  },
  
  state() {
    return {
      bannerList: [] as BannerItem[]
    }
  },
  actions: {
    // 拿轮播图数据
    async getBannerList() {
      const res = await request.get<IApiRes<BannerItem[]>>(&#39;/home/banner&#39;)
      console.log(&#39;拿轮播图数据&#39;, res)
      this.bannerList = res.data.result
    }
  }
})
Nach dem Login kopieren

Typerkennung

// 所有的接口的通用类型
export interface IApiRes<T> {
  msg: string,
  result: T
}

// 轮播图数据中的项
export type BannerItem = {
  id: string;
  imgUrl: string;
  hrefUrl: string;
  type: string;
}
Nach dem Login kopieren

Komponenten auf Seitenebene

<script lang="ts" setup>
import useStore from &#39;@/store&#39;;
const { home } = useStore()
// 发请求
home.getBannerList()

</script>
<template>
  <div class="home-banner">
    <!-- 轮播图子组件 -->
    <XtxCarousel :slides="home.bannerList" :autoPlay="true" :duration="1000"/>
  </div>
</template>

<style scoped lang="less">
.home-banner {
  width: 1240px;
  height: 450px;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 98;
  background-color: #ccc;
}
/deep/ .xtx-carousel .carousel-btn.prev {
  left: 270px !important;
}
/deep/ .xtx-carousel .carousel-indicator {
  padding-left: 250px;
}
</style>
Nach dem Login kopieren

Globale Komponenten

<script lang="ts" setup name="XtxCarousel">
import { BannerItem } from &#39;@/types/data&#39;
import { onBeforeUnmount, onMounted, ref } from &#39;vue&#39;;
// 定义props
const { slides, autoPlay, duration } = defineProps<{
  slides: BannerItem[], 
  autoPlay?: boolean, // 是否开启自动播放
  duration?: number // 自动播放的间隔时间
}>()

// 当前哪个图片选中 高亮
const active = ref(1)

// 点击右侧箭头++
const hNext = () => {
  active.value++
  if(active.value === slides.length){
    active.value = 0
  }
}

// 点击左侧箭头--
const hPrev = () => {
  active.value--
  if(active.value < 0){
    active.value = slides.length - 1
  }
}

// 如果开启了自动播放,则每隔duration去播放下一张: hNext()
onMounted(() => {
  start()
})

onBeforeUnmount(() => {
  stop()
})

let timer = -1

// 鼠标离开要继续播放
const start = () => {
  if(autoPlay) {
    timer = window.setInterval(() => {
      hNext()
    }, duration)
  }
}

// 鼠标hover要暂停播放
const stop = () => {
  clearInterval(timer)
}
</script>

<template>
  <div class="xtx-carousel" @mouseleave="start()" @mouseenter="stop()">
    <ul class="carousel-body">
      <li class="carousel-item" 
      :class="{ fade: idx === active}"
      v-for="(it, idx) in slides" :key="it.id">
        <RouterLink to="/">
          <img :src="it.imgUrl" alt="" />
        </RouterLink>
      </li>
    </ul>
    <a @click="hPrev" href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  class="carousel-btn prev"><i class="iconfont icon-angle-left"></i></a>
    <a @click="hNext" href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  class="carousel-btn next"><i class="iconfont icon-angle-right"></i></a>
    <div class="carousel-indicator">
      <span
      v-for="(it, idx) in slides"
      :class="{ active: active===idx}"
      @mouseenter="active = idx"
      ></span>
    </div>
  </div>
</template>

<style scoped lang="less">
.xtx-carousel {
  width: 100%;
  height: 100%;
  min-width: 300px;
  min-height: 150px;
  position: relative;
  .carousel {
    &-body {
      width: 100%;
      height: 100%;
    }
    &-item {
      width: 100%;
      height: 100%;
      position: absolute;
      left: 0;
      top: 0;
      opacity: 0; // 不可见
      transition: opacity 0.5s linear;
      &.fade {
        opacity: 1; // 可见
        z-index: 1;
      }
      img {
        width: 100%;
        height: 100%;
      }
    }
    &-indicator {
      position: absolute;
      left: 0;
      bottom: 20px;
      z-index: 2;
      width: 100%;
      text-align: center;
      span {
        display: inline-block;
        width: 12px;
        height: 12px;
        background: rgba(0, 0, 0, 0.2);
        border-radius: 50%;
        cursor: pointer;
        ~ span {
          margin-left: 12px;
        }
        &.active {
          background: #fff;
        }
      }
    }
    &-btn {
      width: 44px;
      height: 44px;
      background: rgba(0, 0, 0, 0.2);
      color: #fff;
      border-radius: 50%;
      position: absolute;
      top: 228px;
      z-index: 2;
      text-align: center;
      line-height: 44px;
      opacity: 0;
      transition: all 0.5s;
      &.prev {
        left: 20px;
      }
      &.next {
        right: 20px;
      }
    }
  }
  &:hover {
    .carousel-btn {
      opacity: 1;
    }
  }
}
</style>
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonSo verwenden Sie vue3+Pinia+TypeScript, um eine gekapselte Karussellkomponente zu implementieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:yisu.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage