Skip to content

Skeleton骨架屏

在数据加载时提供占位效果

事先说明

关于 loading 的初始值,使用 true 无疑是最佳实践,这确保了后续访问字段的存在性

详细请见 渲染时机

INFO

基础用法示例为图片加载的占位操作

需要在 Skeleton 组件外部放一个不可见的图片 用于请求加载

loading 初始值为 true 时,因为 渲染时机 会使得 content插槽 里面的图片不会进行渲染

若不进行此操作 图片将永远无法加载

作用于Skeleton上的css无效

直接在 Skeleton 上设置样式是无效的,因为内部不会有任何元素去接受其样式

简而言之 Skeleton 组件不会也不应该对用户布局产生任何影响,它仅仅相对于一个标识符,以此完成骨架屏的效果,仅此而已

基础用法

Skeleton 的使用不太同于其它框架,在 li-daisySkeleton 作为一个容器,然后借助 daisyUIskeleton 去实现具体的骨架屏效果

例子中的 skeleton 是加了前缀的类名,具体类名取决于你项目中的 daisyUI配置

vue
<template>
  <div>
    <img class="sr-only" src="https://picsum.photos/300/300" @load="handleImgLoad" />

    <Skeleton :loading="loading" :delay="500">
      <template #content>
        <div class="space-y-3">
          <img
            v-for="i in 3"
            :key="i"
            class="mx-auto w-30 h-30 rounded-md"
            src="https://picsum.photos/300/300"
          />
        </div>
      </template>
      <template #skeleton>
        <div class="space-y-3">
          <div v-for="i in 3" :key="i" class="skeleton mx-auto w-30 h-30 rounded-md" />
        </div>
      </template>
    </Skeleton>
  </div>
</template>

<script setup lang="ts">
import { Skeleton } from 'li-daisy'
import { ref } from 'vue'

const loading = ref(true)

const handleImgLoad = () => {
  loading.value = false
}
</script>

设置遮罩

有时为了让骨架屏更加有层次感,使用遮罩也是必要的

以下代码给出设置遮罩可行的方案

具体思路便是在 skeleton 插槽中使用一个 relative 的父级以及一个 absolute 的遮罩

遮罩层使用渐变背景 bg-gradient-to-t 从底部向顶部渐变,营造出内容逐渐淡出的视觉效果

通过 pointer-events-none 确保遮罩不会拦截用户的交互操作

z-10 确保遮罩在骨架屏内容之上显示

关于遮罩颜色选择:

  • 遮罩的过渡颜色应与骨架屏的背景色保持一致,通常使用 from-base-100from-base-200
  • 如果骨架屏位于卡片或容器中,建议使用该容器的背景色类,如示例中的 from-base-100
  • 调整 from-60%from-50% 的百分比值可以控制渐变的起始位置,数值越大渐变越靠下
  • 如果遮罩效果不明显,可以尝试增加不透明度或调整起始位置,如 from-base-100/90 from-40%
vue
<template>
  <div class="space-y-6">
    <Skeleton :loading="true" :delay="1000">
      <template #skeleton>
        <div class="relative border border-base-300 rounded-box bg-base-100 overflow-hidden">
          <ul class="list flex flex-col divide-y divide-base-300">
            <li v-for="i in 3" :key="i" class="p-4 space-y-3">
              <div class="grid items-center gap-4" style="grid-template-columns: auto 1fr auto">
                <div class="skeleton opacity-60 size-10 rounded-full"></div>

                <div class="space-y-2">
                  <div class="skeleton opacity-60 w-36 h-3 rounded-box"></div>
                  <div class="skeleton opacity-60 w-24 h-2 rounded-box"></div>
                </div>

                <div class="skeleton opacity-60 h-8 w-8 rounded-box"></div>
              </div>

              <div class="skeleton opacity-60 w-[50%] h-3 rounded-box"></div>
            </li>
          </ul>

          <div
            class="absolute bottom-0 left-0 right-0 top-32 pointer-events-none z-10 bg-gradient-to-t from-base-100 from-60% to-transparent"
          ></div>
        </div>
      </template>
    </Skeleton>
  </div>
</template>

<script setup lang="ts">
import { Skeleton } from 'li-daisy'
</script>

设置count

组件并未提供设置 count 的属性,而是建议手动去设置数量,因为此时可以确保布局的可控性

比如 上述例子 中就是使用简单的 v-for 去实现类似的效果

这样最大的好处就是可以极大统一 contentskeleton 插槽中的元素结构

设置delay

通过设置 delay 来设置延迟效果

当网络请求较快时,较容易出现闪烁的现象,通过设置这项,用户可以得到较好的视觉效果,默认值为 300(单位为ms)

渲染说明

注意:由于骨架屏采用客户端条件渲染,爬虫访问时将获取到骨架屏占位符而非实际内容

如需 SEO 支持,建议在服务端预加载数据或采用其他 SSR 方案。

说明skeletoncontent 插槽基于 loading 值进行条件渲染(使用 v-if

loadingfalse 时,骨架屏隐藏,内容显示

由于使用 v-if 因此可以安全地在 content 插槽中直接访问异步数据,无需额外的空值检查

API

Attributes

Skeleton

属性值说明类型默认值
loading加载状态boolean-
delay延迟时间/msnumber300
count骨架数目number1

Slots

Skeleton

插槽名说明
content实际要渲染的内容
skelton骨架屏内容