如何在Storybook中实现导航菜单组件嵌套文本链接?
问题解答
首先,你当前的代码存在核心问题:forEach 没有返回值(执行后返回 undefined),所以 Desktop.args.options 实际是 [undefined],完全达不到渲染多个链接的效果。而且你修改 Link.args 的操作完全没必要——Link 是单独的文本链接测试用例,和导航菜单的渲染逻辑无关。
正确实现方式
你不需要在story里遍历 LinkOptions,直接把这个数组传给 NavMenu 的 options 属性即可,让 NavMenu 组件内部负责遍历数组并渲染每个 TextLink。
修正后的代码:
const LinkOptions = [ { label: 'Link 1', underline: 'hover', href: '/link1' }, { label: 'Link 2', underline: 'hover', href: '/link2' }, { label: 'Link 3', underline: 'hover', href: '/link3' }, { label: 'Link 4', underline: 'hover', href: '/link4' }, { label: 'Link 5', underline: 'hover', href: '/link5' }, { label: 'Link 6', underline: 'hover', href: '/link6' }, ]; const Template = (args) => <NavMenu {...args} />; const LinkTemplate = (args) => <TextLink {...args} />; export const Desktop = Template.bind({}); export const Link = LinkTemplate.bind({}); // 桌面端:传递完整链接列表 Desktop.args = { options: LinkOptions, ariaLabel: 'Navigation Menu', }; // 平板端:只显示前4个链接 export const Tablet = Template.bind({}); Tablet.args = { options: LinkOptions.slice(0, 4), ariaLabel: 'Tablet Navigation Menu', }; // 移动端:只显示前3个链接 export const Mobile = Template.bind({}); Mobile.args = { options: LinkOptions.slice(0, 3), ariaLabel: 'Mobile Navigation Menu', };
关于 forEach vs map
这里根本不需要在story里用 forEach 或 map 处理数组——story的作用是传递props给组件,渲染逻辑应该封装在 NavMenu 组件内部。如果你的 NavMenu 还没实现遍历逻辑,组件内部应该这样写:
// NavMenu组件示例实现 const NavMenu = ({ options, ariaLabel }) => { return ( <nav aria-label={ariaLabel}> {options.map((linkProps, index) => ( <TextLink key={index} {...linkProps} /> ))} </nav> ); };
组件内部用 map 遍历 options,返回对应的 TextLink 元素,这才是正确的渲染逻辑。
后续测试建议
- 针对hover、Tab键交互等场景,可以直接在Storybook的交互面板中手动测试,或添加
play函数模拟用户操作。 - 不同端的story除了用
slice截取链接数组,还可以传递额外的布局props(比如isMobile),让组件适配不同屏幕的样式。
内容的提问来源于stack exchange,提问作者user632674
相关产品推荐
相关产品推荐

