并行加载示例
通过使用多个 <Gueleton> 组件,可以在一个页面中实现并行加载的效果。占位骨架屏会根据各自的加载状态独立显示和隐藏。
下面是一个示例,其中有两个推特卡片组件和一个用户信息组件,它们会并行加载数据并显示各自的骨架屏。
点击 Reload Data 按钮可以重新加载所有组件的数据。
全部的配置选项
<template> <div class="flex gap-4 p-4"> <Gueleton :data="data" :data-key="dataKey" :loading="userInfoLoading" :limit="limit" :type="type" :fuzzy="fuzzy" :bone="bone" :container="container" v-slot="{ data }" > <UserCard class="flex-none w-48" avatar="https://i.pravatar.cc/150?img=3" name="Jane Doe" username="janedoe" bio="Lover of technology and nature." :followers="1200" :following="300" /> </Gueleton>
<div class="flex flex-col gap-4"> <Gueleton :data="data" :data-key="dataKey" :loading="loading" :limit="limit" :type="type" :fuzzy="fuzzy" :bone="bone" :container="container" v-slot="{ data }" > <TweetCard v-bind="data?.[0]" /> </Gueleton>
<Gueleton :data="data" :data-key="dataKey" :loading="card2Loading" :limit="limit" :type="type" :fuzzy="fuzzy" :bone="bone" :container="container" v-slot="{ data }" > <TweetCard v-bind="data?.[1]" /> </Gueleton> </div></div></template>
<script setup>import { computed, ref, watch } from 'vue'import TweetCard from './TweetCard.vue';import UserCard from './UserCard.vue';
import { gueletonOptions } from '../../../store/gueleton-options';import { useStore } from '@nanostores/vue';
const $gueletonOptions = useStore(gueletonOptions);
const dataKey = computed(() => $gueletonOptions.value.dataKey);const data = computed(() => $gueletonOptions.value.data);const loading = computed(() => $gueletonOptions.value.loading);
const limit = computed(() => $gueletonOptions.value.limit);
const fuzzy = computed(() => $gueletonOptions.value.fuzzy);const type = computed(() => $gueletonOptions.value.type);const bone = computed(() => $gueletonOptions.value.bone);const container = computed(() => $gueletonOptions.value.container);
const userInfoLoading = ref(loading.value);watch(loading, async (newVal) => { if (newVal) { userInfoLoading.value = true; } else { await new Promise(resolve => setTimeout(resolve, Math.random() * 1000 * 2)); userInfoLoading.value = false; }});
const card2Loading = ref(loading.value);watch(loading, async (newVal) => { if (newVal) { card2Loading.value = true; } else { await new Promise(resolve => setTimeout(resolve, Math.random() * 1000 * 2)); card2Loading.value = false; }});</script><template> <aside class="p-4 border rounded-lg shadow-sm bg-white flex flex-col items-center"> <div class="mb-3"> <img class="h-20 w-20 rounded-full object-cover" :src="avatar" alt="avatar" /> </div> <div class="text-center"> <div class="font-semibold text-lg">{{ name }}</div> <div class="text-gray-500 text-sm mb-2">@{{ username }}</div> <div class="text-gray-700 text-sm mb-4">{{ bio }}</div> </div> <div class="flex gap-6 mb-4"> <div class="text-center"> <div class="font-bold text-base">{{ followers }}</div> <div class="text-xs text-gray-500">followers</div> </div> <div class="text-center"> <div class="font-bold text-base">{{ following }}</div> <div class="text-xs text-gray-500">following</div> </div> </div> <button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition">Follow</button> </aside></template>
<script setup lang="ts">defineProps<{ avatar: string name: string username: string bio?: string followers: number following: number}>()</script><template> <!-- Summary Card (thumbnail) - Tailwind CSS --> <div class="p-4 border rounded-lg shadow-sm bg-white not-content"> <!-- Tweet header --> <div class="flex items-start gap-3"> <div class="h-12 w-12"> <img class="size-full rounded-full object-cover" :src="avatar" alt="avatar"> </div> <div class="flex-1"> <div class="flex items-center gap-2"> <span class="font-semibold text-sm">{{ author }}</span> <span class="text-gray-500 text-sm">@user · {{ date }}</span> </div> <p class="mt-2 text-gray-800"> {{ content }} </p> </div> </div>
<!-- Tweet actions --> <div class="mt-3 flex items-center justify-between text-gray-500 text-sm"> <div class="flex gap-6"> <button class="flex items-center gap-2 hover:text-blue-500">💬 <span>{{ comments }}</span></button> <button class="flex items-center gap-2 hover:text-green-500">🔁 <span>{{ retweets }}</span></button> <button class="flex items-center gap-2 hover:text-red-500">❤️ <span>{{ likes }}</span></button> </div> <div class="text-xs">Translate</div> </div> </div>
</template>
<script setup lang="ts">import type { TweetCard } from '../../../lib/mock-utils';
defineProps<TweetCard>();</script>