vue3自定义全局指令实现骨架屏效果

250 阅读1分钟

1.实现骨架屏动画CSS

.bee-skeleton {
  background: linear-gradient(-45deg, #f1f2f3 25%, #fff 45%, #f1f2f3 65%);
  background-size: 400% 100%;
  animation: skeleton-loading 2s ease-in-out infinite;
}

@keyframes skeleton-loading {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0 50%;
  }
}

2.注册全局自定义指令

// 判断是否加骨架屏的动画效果
function setClassName(el, boolean) {
  if (typeof boolean !== 'boolean') return
  const classList = [...el.classList]
  if (boolean) {
    if (classList.includes('bee-skeleton')) return
    el.classList.add('bee-skeleton')
  } else {
    el.classList.remove('bee-skeleton')
  }
}
export default {
  // 初始时调用
  mounted(el, binding) {
    setClassName(el, binding.value)
  },
  // 数据值变化调用
  updated(el, binding) {
    setClassName(el, binding.value)
  },
}

在src/directives/index.js中导入所有自定义指令并注册

import skeleton from './skeleton'

// 汇总自定义指令
const directives = { skeleton }

// 导出自定义指令
export default {
  install(app) {
    Object.keys(directives).forEach(key => {
      // 将每个directive注册到app中
      app.directive(key, directives[key])
    })
  }
}

在src/main.js中导入自定义指令,并全局注册

import directives from '@/directives/index.js'
const app = createApp(App)
// 全局注册
app.use(directives)

app.mount('#app')

3.普通组件内使用

<div style="width: 100%;height: 200px;" v-skeleton="true"></div>

4.若为复杂的样式使用切图放入封装组件使用

封装组件,传入切图

<template>
  <div class="skeleton">
    <div
      :style="{
        minWidth: minWidth + 'px',
        minHeight: minHeight + 'px',
        background: `url(${src}) no-repeat center`,
        backgroundSize: 'contain',
      }"
    ></div>
  </div>
</template>

<script setup>
defineProps({
  minWidth: {
    type: Number,
    default: 335,
  },
  minHeight: {
    type: Number,
    default: 197,
  },
  src: {
    type: String,
    default: require("@/assets/radar01.svg"),
  },
});
</script>
<style scoped lang='less'>
.skeleton {
  width: 100%;
  z-index: 3;
  position: absolute;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>

使用

<template>
  <div>
    <div class="use-skeleton" v-if="isLoading" v-skeleton="true">
      <Skeleton :src="require('@/assets/Skeletion-Pic2.svg')"/>
    </div>
    <div v-else>
      <!-- 加载完成显示.... -->
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";

import Skeleton from "./SkeletonScreen.vue";

const isLoading = ref(true)

setTimeout(() => {
  isLoading.value = false;
}, 3000)

</script>
<style scoped lang='less'>
.use-skeleton {
  width: 100%;
  height: 181px;
}
</style>