如何为Storybook中自定义渲染的Vue 3故事生成正确源码?
Storybook Vue3自定义渲染故事的源码展示问题
我在Storybook中为Vue3组件编写自定义渲染的故事时,渲染结果正确,但生成的展示源码不符合预期,具体示例如下:
示例1
故事代码
export const Story1 = { args: { label: "ButtonLabel" }, render: (args) => ({ components: { MyButton }, setup() { return {args} }, template: `<MyButton>{{args.label}}</MyButton>`, }), };
预期源码输出
<MyButton>ButtonLabel</MyButton>
实际源码输出
<MyButton />
示例2
故事代码
export const Story2 = { args: { label: "ButtonLabel" }, render: (args) => ({ components: { MyButton }, setup() { return {args} }, template: `<div><MyButton v-for="count in 3" :key="count">{{args.label}}</MyButton></div>`, }), };
预期源码输出
<div> <MyButton>ButtonLabel</MyButton> <MyButton>ButtonLabel</MyButton> <MyButton>ButtonLabel</MyButton> </div>
实际源码输出
<MyButton v-for="k in 3" key="k" />
我知道可以通过parameters.docs.source.code或parameters.docs.source.transform自定义源码输出,但不知道具体怎么实现上述预期效果,有没有合适的库可以满足需求?
解决方案
方法1:直接指定parameters.docs.source.code
如果每个故事的预期源码是固定的,直接在故事的parameters里硬编码目标HTML即可:
针对示例1:
export const Story1 = { args: { label: "ButtonLabel" }, render: (args) => ({ components: { MyButton }, setup() { return {args} }, template: `<MyButton>{{args.label}}</MyButton>`, }), parameters: { docs: { source: { code: `<MyButton>ButtonLabel</MyButton>` } } } };
针对示例2:
export const Story2 = { args: { label: "ButtonLabel" }, render: (args) => ({ components: { MyButton }, setup() { return {args} }, template: `<div><MyButton v-for="count in 3" :key="count">{{args.label}}</MyButton></div>`, }), parameters: { docs: { source: { code: `<div> <MyButton>ButtonLabel</MyButton> <MyButton>ButtonLabel</MyButton> <MyButton>ButtonLabel</MyButton> </div>` } } } };
方法2:使用parameters.docs.source.transform动态生成
如果需要根据args动态生成源码,用transform函数处理——它接收当前故事的上下文(包含args),返回最终要展示的源码字符串:
示例1的动态处理:
export const Story1 = { args: { label: "ButtonLabel" }, render: (args) => ({ components: { MyButton }, setup() { return {args} }, template: `<MyButton>{{args.label}}</MyButton>`, }), parameters: { docs: { source: { transform: (story) => { const { label } = story.args; return `<MyButton>${label}</MyButton>`; } } } } };
示例2的动态处理:
export const Story2 = { args: { label: "ButtonLabel", count: 3 }, // 将count设为args,方便动态修改 render: (args) => ({ components: { MyButton }, setup() { return {args} }, template: `<div><MyButton v-for="num in args.count" :key="num">{{args.label}}</MyButton></div>`, }), parameters: { docs: { source: { transform: (story) => { const { label, count } = story.args; const buttons = Array(count).fill(` <MyButton>${label}</MyButton>`).join('\n'); return `<div>\n${buttons}\n</div>`; } } } } };
推荐工具库
如果需要复杂的模板编译、格式化逻辑,可使用以下轻量库:
- html-tags:自动补全HTML标签、格式化缩进,让输出源码更规整
- mustache:简单模板引擎,方便根据args填充模板内容
比如结合mustache实现动态源码生成:
import mustache from 'mustache'; // 预定义模板 const story2Template = `<div> {{#count}} <MyButton>{{label}}</MyButton> {{/count}} </div>`; export const Story2 = { args: { label: "ButtonLabel", count: 3 }, render: (args) => ({ components: { MyButton }, setup() { return {args} }, template: `<div><MyButton v-for="num in args.count" :key="num">{{args.label}}</MyButton></div>`, }), parameters: { docs: { source: { transform: (story) => { // 生成对应长度的数组供mustache遍历 const data = { ...story.args, count: Array(story.args.count).fill(null) }; return mustache.render(story2Template, data); } } } } };
内容的提问来源于stack exchange,提问作者oemera
相关产品推荐
相关产品推荐

