如何在Storybook中为Vue组件配置VueRouter的$route参数?
解决Vue组件在Storybook中模拟$route的问题
我正在给一个依赖this.$route.params的Vue组件编写Storybook故事,但不知道如何在Storybook环境中模拟$route对象。尝试用decorators但只会做渲染相关的包裹操作,不知道怎么注入值。找过专门的storybook-router工具,但它多年未维护,语法和新版Storybook不兼容,没法用。
组件里的关键代码:
mounted() { axios.get(`.../bla/${this.$route.params.id}.json`) },
现在Storybook会抛出错误:TypeError: Cannot read properties of undefined (reading 'params')
两种可行的解决方案
不用第三方库,直接通过Storybook的装饰器(Decorators)就能搞定,下面是两种实用方法:
方法1:创建局部VueRouter实例(完整路由模拟)
如果需要完整的路由功能,比如路由跳转等,可以在装饰器里初始化一个VueRouter实例,定义匹配的路由和参数:
import AssetShow from '../app/javascript/src/site/components/assets/Show' import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) export default { title: 'Site/AssetShow', component: AssetShow, }; // 自定义模拟的路由参数 const mockRouteParams = { id: '123' } export const CustomerSpotlight = () => ({ components: { AssetShow }, template: '<AssetShow />', }); CustomerSpotlight.decorators = [ () => ({ // 初始化路由实例,定义匹配当前组件的路由 router: new VueRouter({ routes: [ { path: '/assets/:id', component: AssetShow } ] }), // 用router-view渲染组件,自动注入$route template: '<router-view />' }) ];
方法2:直接注入$route对象(轻量模拟)
如果只是需要$route.params这类基础数据,不需要完整路由功能,可以直接在装饰器里模拟$route并挂载到Vue实例上:
import AssetShow from '../app/javascript/src/site/components/assets/Show' export default { title: 'Site/AssetShow', component: AssetShow, }; export const CustomerSpotlight = () => ({ components: { AssetShow }, template: '<AssetShow />', }); CustomerSpotlight.decorators = [ (story) => ({ components: { story }, data() { return { // 模拟需要的$route结构 $route: { params: { id: '123' } } } }, beforeMount() { // 将模拟的$route挂载到根实例,让组件能通过this.$route访问 this.$root.$route = this.$route }, template: '<story />' }) ];
补充:全局装饰器(多组件复用)
如果多个组件都需要模拟$route,可以在.storybook/preview.js中添加全局装饰器,避免重复代码:
import Vue from 'vue' export const decorators = [ (story) => ({ components: { story }, data() { return { $route: { params: { id: 'default-id' } } } }, beforeMount() { this.$root.$route = this.$route }, template: '<story />' }) ]
单个故事需要自定义参数时,直接在对应故事的装饰器里覆盖即可。
内容的提问来源于stack exchange,提问作者emersonthis
相关产品推荐
相关产品推荐

