Vue 3 自定义指令 — 骨架屏

Vue 3 自定义指令 — 骨架屏
文章图片

前言 骨架屏是页面的一个空白版本,通常会在页面完全渲染之前,通过一些灰色的区块大致勾勒出轮廓,待数据加载完成后,再替换成真实的内容。
目前主流 UI库 都有骨架屏,如 Element-UIAntd
可以看到使用起来非常简单,只需要一行代码即可

// element // antd

但这样不够灵活,对于追求个性化的页面就不太行了,
后来~ 我想了想,能不能给 节点标记,然后根据 标记 自动生成对应骨架屏呢?
【Vue 3 自定义指令 — 骨架屏】结果还真给我想出来了! 用 指令
先看效果 o((>ω< ))o ~
Vue 3 自定义指令 — 骨架屏
文章图片


实现原理 我们 自定义2个指令,分别叫做 skeletonskeleton-item
// skeleton.ts import { reactive, watchEffect, h, render } from 'vue'const state = reactive({ // 加载状态 loading: false, // 使用了 v-skeleton-item 指令的节点保存在这里 list: [] })watchEffect(() => { // 创建 vnode const children = state.list.map((el) => h('div', { style: { position: 'absolute', top: el.getBoundingClientRect().top + 'px', left: el.getBoundingClientRect().left + 'px', width: el.getBoundingClientRect().width + 'px', height: el.getBoundingClientRect().height + 'px', background: '#e5e5e5', borderRadius: getComputedStyle(el).borderRadius, }, }) ); // 创建 div 容器 const container = h('div', children)// 将 div容器 渲染到 body 中 render(state.loading ? container : null, document.body) })const Skeleton = { mounted(el, binding) { state.loading = binding.value }, updated(el, binding) { state.loading = binding.value }, unmounted(el) { state.loading = false } }const SkeletonItem = { mounted(el, binding) { // 保存 el state.list.push(el) }, unmounted(el) { // 删除 el const i = state.list.indexOf(el) if (i == -1) return state.list.splice(i, 1) } }// 注册这2个指令 export default { install: app => { app.directive('skeleton', Skeleton) app.directive('skeleton-item', SkeletonItem) } }export { Skeleton, SkeletonItem }

点击(在线运行)示例代码
实现原理其实很简单
  1. 我们先自定义2个指令,分别叫做
    skeleton: 用于控制 loading 状态
    skeleton-item: 用于标记需要创建骨骼的节点

  2. SkeletonItemmounted 钩子函数将 el 保存到 list 里面

  3. 遍历 list 创建对应的 vnode,
    并且调用 el.getBoundingClientRect() 获取 el 的位置大小设置给 vnode,
    使 vnodeel 正好重叠在一个位置

  4. 最后调用 render(state.loading ? container : null, document.body)骨架屏 渲染出来。(state.loading 是由 skeleton 指令控制的)
@x-ui-vue3/skeleton 就是基于以上思路进行封装的一个 vue3 指令。 我们来看看如何使用 安装
npm i -S @x-ui-vue3/skeleton

main.js
import { createApp } from 'vue' import Skeleton from '@x-ui-vue3/skeleton' import App from './App.vue'createApp(App).use(Skeleton).mount('#app')

App.vue

Vue 3 自定义指令 — 骨架屏
文章图片

更多示例 Vue 3 自定义指令 — 骨架屏
文章图片

Vue 3 自定义指令 — 骨架屏
文章图片


  • DEMO 1
  • DEMO 2
  • DEMO 3
最后
你的点赞?对我非常重要,也是我坚持的动力

    推荐阅读