VUE3 骨架屏的封装

207 阅读1分钟

基础知识

使用ElementPlus封装的组件

组件 | Element

Vue3组件封装(setup语法糖)

优点

  • 更少、更简洁的代码,不需要使用 return {} 暴露变量和方法了,使用组件时不需要主动注册了;
  • 更好的 Typescript 支持,使用纯 Typescript 声明 props 和抛出事件,不会再像 option api 里那么蹩脚了;
  • 更好的运行时性能;

实现

  1. 在components下新建Skeleton,index.vue
<script setup lang="ts">
defineProps({
    bg: {
        type: String,
        default: '#efefef'
    },
    width: {
        type: String,
        default: '100px'
    },
    height: {
        type: String,
        default: '100px'
    },
    animated: {
        type: Boolean,
        default: false
    }
})
</script>

<template>
    <div class="skeleton" :style="{ width, height }" :class="{ shan: animated }">
        <div class="block" :style="{ backgroundColor: bg }"></div>
    </div>
</template>

<style scoped lang="scss">
.skeleton {
    display: inline-block;
    position: relative;
    overflow: hidden;
    vertical-align: middle;

    .block {
        width: 100%;
        height: 100%;
        border-radius: 2px;
    }
}

.shan {
    &::after {
        content: "";
        position: absolute;
        animation: shan 1.5s ease 0s infinite;
        top: 0;
        width: 50%;
        height: 100%;
        background: linear-gradient(to left,
                rgba(255, 255, 255, 0) 0,
                rgba(255, 255, 255, 0.3) 50%,
                rgba(255, 255, 255, 0) 100%);
        transform:skewX(-45deg);
    }
}
@keyframes shan{
    0%{
        left:-100%;
    }
    100%{
        left:120%;
    }
}
</style>
  1. components下新建index.ts 引入
import Skeleton from './Skeleton/index.vue';
import type { App } from 'vue';

export const componentsPlugin = {
  install(app: App<Element>) {
    app.component('Skeleton', Skeleton);
  }
};

3.全局引入

import { componentsPlugin } from '@/components'
app.use(componentsPlugin)
.mount('#app')

4.组件使用(二次封装)

<script setup lang="ts">
defineProps({
    bg: {
        type: String,
        default: '#efefef'
    }
})
</script>

<template>
    <div class='home-skeleton'>
        <div class="item" v-for="i in 4" :key="i" :style="{ backgroundColor: bg }">
            <Skeleton bg="#e4e4e4" width="306px" height="306px" animated />
            <Skeleton bg="#e4e4e4" width="200px" height="24px" animated />
            <Skeleton bg="#e4e4e4" width="120px" height="22px" animated />
        </div>
    </div>
</template>

<style scoped lang="scss">
.home-skeleton {
    width: 1240px;
    height: 406px;
    display: flex;
    justify-content: space-between;

    .item {
        width: 306px;

        .skeleton~.skeleton {
            display: block;
            margin: 16px auto 0;

        }
    }
}
</style>

5.使用示例

<ul class="goods-list" v-if="newList.length">
                <li v-for="item in newList" :key="item.id">
                    <RouterLink :to="`/detail/${item.id}`">
                        <img :src="item.picture" alt="">
                        <p class="name">{{ item.name }}</p>
                        <p class="price">&yen;{{ item.price }}</p>
                    </RouterLink>
                </li>
</ul>
<HomeSkeleton v-else/>