189 lines
4.1 KiB
Vue
189 lines
4.1 KiB
Vue
<script lang="ts">
|
||
import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic';
|
||
import { defineColadaLoader } from 'unplugin-vue-router/data-loaders/pinia-colada';
|
||
|
||
async function getUserById(userId: string, { signal }: { signal?: AbortSignal }) {
|
||
console.warn('[getUserById] 被调用, userId :>> ', userId);
|
||
setTimeout(() => {
|
||
console.log('10s 已过', 'userId :>> ', userId);
|
||
}, 1000 * 10);
|
||
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`, { signal });
|
||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||
return await res.json();
|
||
}
|
||
|
||
export const useUserData = defineColadaLoader('DataLoadersIdSub1UserId', {
|
||
async query(to, { signal }) {
|
||
console.debug('[defineColadaLoader] query');
|
||
return getUserById(to.params.userId, { signal });
|
||
},
|
||
key: (to) => ['users', to.params.userId],
|
||
// Keep the data "fresh" 10 seconds to avoid fetching the same data too often
|
||
// 保持数据“新鲜”10秒,以避免过于频繁地获取相同的数据
|
||
staleTime: 1000 * 10,
|
||
});
|
||
|
||
export const usePageData = defineBasicLoader('DataLoadersIdSub1UserId', async (route) => {
|
||
console.warn('[defineBasicLoader] 被调用, userId :>> ', route.params.userId);
|
||
await new Promise((resolve) => setTimeout(resolve, 777));
|
||
return { idFromPreviousPage: route.params.id, someOtherData: 'someOtherData' };
|
||
});
|
||
</script>
|
||
|
||
<script setup lang="ts">
|
||
const { data: user, status, error, isLoading, reload, refresh } = useUserData();
|
||
|
||
const route = useRoute('DataLoadersIdSub1UserId');
|
||
</script>
|
||
|
||
<template>
|
||
<div flex="~ row">
|
||
<button class="green" @click="$router.back()">Back</button>
|
||
</div>
|
||
<h1>Pinia Colada Loader Example</h1>
|
||
<pre>route.params: {{ route.params }}</pre>
|
||
|
||
<fieldset class="flex items-center gap-4">
|
||
<legend>Controls</legend>
|
||
|
||
<button @click="refresh()">Refresh</button>
|
||
<button @click="reload()">Refetch</button>
|
||
</fieldset>
|
||
|
||
<div class="flex items-center">
|
||
<RouterLink :to="{ params: { userId: (Number(route.params.userId) || 0) - 1 } }">
|
||
Previous
|
||
{{ (Number(route.params.userId) || 0) - 1 }}
|
||
</RouterLink>
|
||
|
|
||
<RouterLink :to="{ params: { userId: (Number(route.params.userId) || 0) + 1 } }">
|
||
Next {{ (Number(route.params.userId) || 0) + 1 }}
|
||
</RouterLink>
|
||
</div>
|
||
|
||
<h2>State</h2>
|
||
|
||
<p>
|
||
<code>status: {{ status }}</code>
|
||
<br />
|
||
<code>isLoading: {{ isLoading }}</code>
|
||
</p>
|
||
<pre v-if="error">Error: {{ error }}</pre>
|
||
<pre v-else>{{ user == null ? String(user) : user }}</pre>
|
||
</template>
|
||
|
||
<style scoped lang="less">
|
||
button {
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 4px;
|
||
border: 1px solid #ccc;
|
||
background: #f5f5f5;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
|
||
&:hover {
|
||
background: #e5e5e5;
|
||
}
|
||
|
||
&.green {
|
||
background: #4caf50;
|
||
color: white;
|
||
border-color: #45a049;
|
||
|
||
&:hover {
|
||
background: #45a049;
|
||
}
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
background: #2a2a2a;
|
||
border-color: #444;
|
||
color: #fff;
|
||
|
||
&:hover {
|
||
background: #333;
|
||
}
|
||
|
||
&.green {
|
||
background: #2e7d32;
|
||
border-color: #1b5e20;
|
||
|
||
&:hover {
|
||
background: #1b5e20;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
fieldset {
|
||
border: 1px solid #ddd;
|
||
border-radius: 6px;
|
||
padding: 1rem;
|
||
margin: 1rem 0;
|
||
|
||
legend {
|
||
padding: 0 0.5rem;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
border-color: #444;
|
||
background: #1a1a1a;
|
||
}
|
||
}
|
||
|
||
pre {
|
||
background: #f8f8f8;
|
||
padding: 1rem;
|
||
border-radius: 4px;
|
||
overflow-x: auto;
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
background: #1a1a1a;
|
||
color: #e0e0e0;
|
||
}
|
||
}
|
||
|
||
.flex.items-center {
|
||
a {
|
||
color: #2196f3;
|
||
text-decoration: none;
|
||
padding: 0.5rem;
|
||
|
||
&:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
color: #64b5f6;
|
||
|
||
&:hover {
|
||
color: #90caf9;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
code {
|
||
background: #f1f1f1;
|
||
padding: 0.2rem 0.4rem;
|
||
border-radius: 3px;
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
background: #2a2a2a;
|
||
color: #e0e0e0;
|
||
}
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:deep(body) {
|
||
background: #121212;
|
||
color: #e0e0e0;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<route lang="yaml">
|
||
meta:
|
||
layout: second
|
||
</route>
|