Storybook Vue3 Router
一個 Storybook 裝飾器,讓您可以使用您的 Vue 3 具路由功能的元件。
如果您想使用 <router-view>
或 <router-link>
為 Vue 3 元件建立 stories,那麼您需要使用 vue-router
包裹您的 stories,這個擴充功能將讓您輕鬆完成此操作。
對於只需要存取 $route
和 $router
屬性的使用者,還有一個 模擬路由器裝飾器 選項。
如何使用
這個裝飾器適用於 Storybook 的 Component Story Format (CSF) 和 hoisted CSF annotations,這是自 Storybook 6 以來推薦的撰寫 stories 方式。它尚未在 storiesOf API 中進行測試。
Storybook v6:請使用套件版本 2.x
Storybook v7:請使用套件版本 3+
請參閱 遷移指南。
安裝裝飾器
npm install --save-dev storybook-vue3-router
// or
yarn add --dev storybook-vue3-router
在您的 stories 中使用
預設設定將建立一個 vue-router
實例,其中包含 2 個路由(/
和 /about
) - 這些可以在 defaultRoutes.ts 檔案中檢視。
/* import storybook-vue3-router */
import { vueRouter } from 'storybook-vue3-router'
/* ...story setup... */
/* your story export */
export const Default = Template.bind({})
/* adding storybook-vue3-router decorator */
Default.decorators = [
/* this is the basic setup with no params passed to the decorator */
vueRouter()
]
範例
您可以在這個 demo 上看到發布的 範例 stories。
進階使用
此裝飾器帶有可選參數,用於自訂 Storybook 中 vue-router
的實作。
自訂路由
/* define our custom routes */
const customRoutes = [
{
path: '/',
name: 'home',
component: HomeComponent // this would need to be defined/imported into the `.stories` file
},
{
path: '/about',
name: 'about',
component: AboutComponent // this would need to be defined/imported into the `.stories` file
}
]
/* adding storybook-vue3-router decorator */
Default.decorators = [
/* pass custom routes to the decorator */
vueRouter(customRoutes)
]
自訂路由(帶有守衛)
/* define our custom routes */
const customRoutes = [
// ...
{
path: '/admin',
name: 'admin',
component: AdminComponent,
/* add per-route navigation guard */
beforeEnter: (to, from, next) => {
// ...
}
}
]
/* adding storybook-vue3-router decorator */
Default.decorators = [
/* pass custom routes to the decorator */
vueRouter(customRoutes)
]
自訂路由(帶有初始路由)
預設情況下,裝飾器會將起始路由預設為 /
,如果您想變更此設定,可以作為參數傳遞給裝飾器
/* define our custom routes */
const customRoutes = [
{
path: '/',
name: 'dashboard',
component: Dashboard
},
{
path: '/intro',
name: 'intro',
component: Intro
}
]
### With Router Options
We can pass [Vue Router options](https://router.vuejs.org/api/index.html#history) into our decorator.
```typescript
/* adding storybook-vue3-router decorator */
Default.decorators = [
/* pass vueRouterOptions to the decorator */
vueRouter(undefined, {
vueRouterOptions: {
linkActiveClass: 'my-active-class',
linkExactActiveClass: 'my-exact-active-class'
...etc
}
})
]
router.isReady()
如果您使用 router.isReady()
設置了路由器,和/或您的元件需要在建立生命週期掛鉤上具有特定的路由/路由數據,您可能需要使用 asyncVueRouter
導出。
此導出提供路由器,直到路由器準備好才會渲染 story。
Story 設定
import { asyncVueRouter } from 'storybook-vue3-router'
/* define our custom routes */
const customRoutes = [
{
path: '/',
name: 'dashboard',
component: Dashboard
},
{
path: '/intro',
name: 'intro',
component: Intro
}
]
/* adding storybook-vue3-router decorator */
Default.decorators = [
/* pass initialRoute to the decorator */
asyncVueRouter(customRoutes, {
initialRoute: '/intro'
})
]
Preview.js 異步設定
為了使用 async
路由器設定方法,您需要修改您的 .storybook/preview.js 檔案,以使用 Vue 3 的 <Suspense>
元件包裹 stories。這是因為裝飾器需要一個 async setup()
才能正確地 await router.isReady()
。您可以將預覽修改為
const preview = {
decorators: [
(story) => ({
components: { story },
template: '<Suspense><story /></Suspense>',
}),
],
};
export default preview;
有關更進階的使用方式,請參閱 範例資料夾。
裝飾器參數
function vueRouter(routes: RouteRecordRaw[], options?: { initialRoute?: string, beforeEach?: NavigationGuard, vueRouterOptions?: RouterOptions })
function asyncVueRouter(routes: RouteRecordRaw[], options?: { initialRoute?: string, beforeEach?: NavigationGuard, vueRouterOptions?: RouterOptions })
模擬路由器
並非總是需要完整的 vue-router
- 例如,如果您沒有使用 <router-view>
或 <router-link>
的元件,則使用 mockRouter
導出可能會滿足您的需求(並減少您的 stories 中使用的導入)。
注意:mockRouter
僅適用於使用選項 API this.$route
和/或 this.$router
的情況,不適用於使用 vue router composables(例如 useRoute()
和 useRouter()
)的使用案例。
在您的 stories 中使用 mockRouter
預設設定將從 vue-router
建立模擬的 $router
和 $route
,這讓您可以為使用程式化導航和基於路由邏輯的元件建立 stories。
我們也可以將自訂選項傳遞到 mockRouter
裝飾器中
{
meta?: Array<string>,
params?: Array<string>,
query?: Array<string>
}
/* import storybook-vue3-router mockRouter */
import { mockRouter } from 'storybook-vue3-router'
/* ...story setup... */
/* your story export */
export const Default = Template.bind({})
/* adding storybook-vue3-router mockRouter decorator */
Default.decorators = [
mockRouter({
meta: ['some_meta'],
params: ['some_param'],
query: ['some_query']
})
]
您可以在我們的 storybook demo 網站和我們的 程式碼範例中看到 mockRouter
的範例
v2.x > v3+ 遷移
⚠️ 重大變更 ⚠️
v3.x 版本不再對 vueRouter
裝飾器使用預設匯出,您需要更新為使用具名匯入
/* DONT */
import vueRouter from 'storybook-vue3-router'
/* DO */
import { vueRouter } from 'storybook-vue3-router'
v1.x > v2.x 遷移
從 v1 的遷移帶來了一些重大變更
// v1.x - 2nd param is used to pass `beforeEach` router guard
// in this example the guard is used to fire a storybook action with `to` and `from` router objects
vueRouter(customRoutes, (to, from) => action('ROUTE CHANGED')({ to: to, from: from })) // LEGACY
// v2.1 - 2nd param is used to pass additional options to the decorator
vueRouter(customRoutes, {
/* add global beforeEach guard */
beforeEach: (to, from) => action('ROUTE CHANGED')({ to: to, from: from })
})
如果您先前在第二個參數中使用 v1 的路由守衛,則需要將其重構為使用 路由特定路由守衛 (建議),或者您可以使用 beforeEach
選項傳遞您的全域路由守衛。
v2.0 沒有此 beforeEach
選項,請升級到 v2.1
⚠️ 警告
當使用全域 beforeEach
選項時,如果現有的 story 也使用此裝飾器,則我們必須強制重新載入頁面,才能設定特定的 story 路由守衛,這會對 UX/效能產生輕微影響。請查看 demo 以取得此範例:README > 使用路由守衛 > 全域守衛 - 當點擊「全域守衛」連結時,您會注意到頁面已重新整理以套用全域守衛(由於先前存在 stories)。
如果您僅將此裝飾器用於一個 story,則不會有這個問題。
在解決 此問題後,為了讓可以使用不同的路由設定建立多個 stories,發現這會導致全域 beforeEach
函數被新增到每個路由上。例如,每次您點擊不同的 story 時,都會新增新的 beforeEach
掛鉤 - 但不會移除先前的掛鉤,這會導致多個守衛在與「作用中」story 無關的 stories 上觸發。