preface


To start!

Why encapsulate

  • In line with the ES6 modular development philosophy
  • Register global components, for better reuse, where you need to directly use the label name

Global components are registered as plugins in Vue3, and unified components in the project are added to the SRC/Components folder in a new carousel.vue file to write code

<template>
  <div class="xtx-carousel" @mouseenter="stop" @mouseleave="start">
    <ul class="carousel-body">
      <li class="carousel-item" v-for="(item, i) in sliders" :key="i" :class="{ fade: index === i }">
        <RouterLink to="/">
          <img :src="item.imgUrl" alt="" />
        </RouterLink>
      </li>
    </ul>
 <! -- Left and right control buttons -->
    <! -- Previous slide -->
    <a @click="toggle(-1)" href="javascript:;" class="carousel-btn prev"><i class="iconfont icon-angle-left"></i></a>
    <! -- Next slide -->
    <a @click="toggle(1)" href="javascript:;" class="carousel-btn next"><i class="iconfont icon-angle-right"></i></a>
     <! -- Pager -->
    <div class="carousel-indicator">
      <span v-for="(item, i) in sliders" :key="i" :class="{ active: index === i }"></span>
    </div>
  </div>
</template>

<script>
import { ref, watch } from 'vue'
export default {
  name: 'XtxCarousel'.props: {
    sliders: {
      type: Array.default: () = >[]},duration: {
      type: Number.default: 1000
    },
    autoplay: {
      type: Boolean.default: false
    }
  },
  setup (props) {
    // Index of images displayed by default
    const index = ref(0)
    // Auto play
    let timer = null
    const autoPlayFn = () = > {
      clearInterval(timer)
      timer = setInterval(() = > {
        index.value++
        if (index.value >= props.sliders.length) {
          index.value = 0
        }
      }, props.duration)
    }
    watch(
      () = > props.sliders,
      newVal= > {
        // Automatic play function is called only when automatic play is enabled
        if (newVal.length > 1 && props.autoplay) {
          index.value = 0
          autoPlayFn()
        }
      },
      { immediate: true})const stop = () = > {
      if (timer) clearInterval(timer)
    }
    const start = () = > {
      if (props.sliders.length && props.autoPlay) {
        autoPlayFn()
      }
    }
    // Go up, go down
    const toggle = step= > {
      index.value += step
      if (index.value >= props.sliders.length) {
        index.value = 0
        return
      }
      if (index.value < 0) {
        index.value = props.sliders.length - 1}}// Component consumption, clear timer
    // onUnmounted(() => {
    // if (timer.value) clearInterval(timer.value)
    // })
    return { index, start, stop, toggle }
  }
}
</script>

<style scoped lang="less">
.xtx-carousel{:deep(.carousel-btn.prev) {
    left: 270px;
  }
  :deep(.carousel-indicator) {
    padding-left: 250px; }}.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.5 s 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.5 s;
      &.prev {
        left: 20px;
      }
      &.next {
        right: 20px; &}}}:hover {
    .carousel-btn {
      opacity: 1; }}}</style>
Copy the code

Registering global components

Create the index.js file in SRC/Components

// Extend vue's original functionality: global components, custom directives, mount prototype methods, note: no global filters.
// This is the plug-in
// Vue 2.0 plugin writing elements: export an object, install function, default passed in the Vue constructor, Vue based extension
// Vue3.0 plug-in writing elements: export an object, install function, default passed app application instance, app based on extension

import XtxCarousel from './xtx-carousel.vue'
export default {
  install (app) {
    // Extend on app, which provides component directive functions
    / / if you want to mount a prototype app. Config. GlobalProperties way
    app.component(XtxCarousel.name, XtxCarousel)
  }
}
Copy the code

thenmain.jsFile registration

import {
  createApp
} from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// Import the reset style
import 'normalize.css'
// Import the global style
import '@/style/common.css'
// Font icon
import '@/assets/icon/iconfont.css'
// A custom plug-in
import XtxUI from '@/components/library'

createApp(App).use(store).use(router).use(XtxUI).mount('#app')
Copy the code

Using the demonstration

Pass in custom attributes as required by the global component, using fixed data to simulate this. You can wrap a div element around the global component to control the size of the multicast diagram component

The code is as follows:

<template>
  <div class="home-banner">
    <XtxCarousel :list="sliders" class="xtx-carousel" />
  </div>
</template>
<script>
import { ref } from 'vue'
import { findBanner } from '@/api/home'
export default {
  name: 'HomeBanner',
  setup () {
    const sliders = ref([])
    findBanner().then(data= > {
      sliders.value = data.result
    })
    console.log(sliders)
    return { sliders }
  }
}
</script>
<style scoped lang="less">
.home-banner {
  width: 1240px;
  height: 500px;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 98;
}
.xtx-carousel{:deep(.carousel-btn.prev) {
    left: 270px;
  }
  :deep(.carousel-indicator) {
    padding-left: 250px; }}</style>
Copy the code