程序员的资源宝库

网站首页 > gitee 正文

vue3项目-小兔鲜儿笔记-03-首页模块02

sanyeah 2024-04-13 16:21:02 gitee 5 ℃ 0 评论

1. 骨架效果

目的:为了在加载过程中等待效果更好,封装骨架屏组件

实现步骤:

  • 骨架屏组件需暴露的属性:高、宽、背景颜色,是否启用动画

  • 使用插件的方式进行全局注册

<template>
  <!-- 骨架屏,就是一个可定制高、宽、背景以及动画的盒子 -->
  <div class="xtx-skeleton" :style="{ width, height, backgroundColor: bg }">
    <!-- 额外多加一个盒子,在这个盒子上添加伪元素,做绝对定位 -->
    <div class="block" :class="{ animate: animated }"></div>
  </div>
</template>

<script setup>
defineProps({
  width: {
    type: String,
    default: '100px'
  },
  height: {
    type: String,
    default: '100px'
  },
  bg: {
    type: String,
    default: '#efefef'
  },
  animated: {
    type: Boolean,
    default: true
  }
})
</script>
<style lang="less" scoped>
.xtx-skeleton {
  position: relative;
  display: inline-block;
  vertical-align: middle;
  overflow: hidden;
  border-radius: 2px;

  .block {
    width: 100%;
    height: 100%;
  }

  .animate {
    &::after {
      content: '';
      // 设置绝对定位,这样动画可以调整left来实现移动的效果
      position: absolute;
      width: 50%;
      height: 100%;
      top: 0;
      // 使用动画,属性:name duration time-function delay iteration
      animation: move 1s ease 0s infinite;
      // 线性渐变,配合伪元素做出一个宽度只有盒子一半的图片,这个图片渐变色为黑白黑,向左倾斜45度,配合动画从左往右移动
      background-image: linear-gradient(to left,
      rgba(255, 255, 255, 0) 0,
      rgba(255, 255, 255, 0.3) 50%,
      rgba(255, 255, 255, 0) 100%);
      transform: skew(45deg);
    }
  }
}

// 动画:从左到右移动
@keyframes move {
  0% {
    left: -100%;
  }
  100% {
    left: 120%;
  }
}
</style>

 

2. 封装轮播图组件

基础布局:

<template>
  <div class="xtx-carousel" @mouseenter="stopAutoPlay()" @mouseleave="startAutoPlay()">
    <!--  banner  -->
    <ul class="carousel-body">
      <template v-if="sliders.length">
        <li
            v-for="(slider, i) in sliders"
            :key="slider.id"
            class="carousel-item"
            :class="{fade: index === i}"
        >
          <router-link :to="slider.hrefUrl">
            <img :src="slider.imgUrl" alt="">
          </router-link>
        </li>
      </template>
    </ul>
    <!--  左右翻页指示器  -->
    <a href="javascript:;" class="carousel-btn prev" @click="toggle(-1)">
      <i class="iconfont icon-angle-left"></i>
    </a>
    <a href="javascript:;" class="carousel-btn next" @click="toggle(1)">
      <i class="iconfont icon-angle-right"></i>
    </a>
    <!--  指示器  -->
    <div class="carousel-indicator">
      <span
          v-for="(slider, i) in sliders"
          :key="slider.id"
          @click="index=i"
          :class="{active: index===i}"
      ></span>
    </div>
  </div>
</template>

 

暴露出轮播图数组、一幅banner的持续时间、是否自动轮播这三个属性,供父组件传入使用

const props = defineProps({
  sliders: {
    type: Array,
    default: []
  },
  duration: {
    type: Number,
    default: 2000
  },
  autoPlay: {
    type: Boolean,
    default: false
  }
})

 

自动轮播的逻辑:定时器令索引值更新,且在鼠标移入的时候清除定时器,鼠标移出的时候重新开启定时器

// 自动轮播
const index = ref(0)
let timer = null
const autoPlayFn = () => {
  clearInterval(timer)
  timer = setInterval(() => {
    index.value++
    if (index.value > props.sliders.length) {
      index.value = 0
    }
  }, props.duration)
}

// 鼠标移入,停止自动轮播
const stopAutoPlay = () => {
  if (timer) {
    clearInterval(timer)
  }
}

// 鼠标移出,如果是要求自动轮播,则开启自动轮播
const startAutoPlay = () => {
  if (props.autoPlay && props.sliders.length) {
    autoPlayFn()
  }
}

// 监听sliders,判断是否要开启自动轮播
watch(() => props.sliders, (newValue) => {
  if (newValue.length && props.autoPlay) {
    index.value = 0
    autoPlayFn()
  }
}, {immediate: true})

// 组件销毁时,销毁定时器
onUnmounted(() => {
  if (timer) {
    clearInterval(timer)
  }
})

 

点击更改轮播图的逻辑:点击上一张就使索引值-1,点击下一张就使索引值+1,判断边界范围

// 点击更改轮播图
const toggle = (step) => {
  let newIndex = index.value + step
  if (newIndex > props.sliders.length - 1) {
    newIndex = 0
  }
  if (newIndex < 0) {
    newIndex = props.sliders.length - 1
  }
  index.value = newIndex
}

 

3. Vue插件的使用

  • Vue2的使用插件的方式:导出一个对象,有install函数,默认传入Vue构造函数,install函数内部使用Vue构造函数扩展Vue功能

  • Vue3的使用插件的方式:导出一个对象,有install函数,默认传入了app应用实例,install函数内部使用app实例扩展Vue功能

import XtxSkeleton from './xtx-skeleton.vue'
import XtxCarousel from '@/components/library/xtx-carousel'

export default {
  install(app) {
    app.component(XtxSkeleton.name, XtxSkeleton)
    app.component(XtxCarousel.name, XtxCarousel)
  }
}

main.js中,app实例使用use方法就会自动调用install函数,并传入app应用实例

import { createApp } from 'vue'
import App from './App.vue'

import { createPinia } from 'pinia'
import persistedState from 'pinia-persistedstate'

import router from './router'

import 'normalize.css'
import '../src/assets/styles/common.less'

import UI from './components/library'

const store = createPinia()
store.use(
  persistedState({
    key: 'erabbit-shop',
    paths: ['user', 'cart']
  })
)

createApp(App).use(router).use(UI).use(store).mount('#app')

 

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表