Storybook报错Target container is not a DOM element:React模态框DOM适配方法
解决Storybook中React模态框Portal目标元素缺失问题
方法1:全局添加目标DOM元素(推荐)
直接修改Storybook的根模板文件,让所有故事页面都包含#portal元素:
- 找到项目中的
.storybook/preview.html文件(如果没有就新建一个) - 在
<body>标签内添加目标元素:
<body> <div id="portal"></div> <!-- 其他原有内容 --> </body>
重启Storybook后,所有故事都会自动加载这个元素,无需在单个组件里额外处理。
方法2:单个Story中动态创建元素
如果只有特定组件需要这个元素,不想全局污染,可以在对应Story里动态创建/销毁元素:
import { useEffect } from 'react'; import YourModalComponent from './YourModalComponent'; export default { title: 'Components/Modal', component: YourModalComponent, }; const Template = (args) => { useEffect(() => { // 创建目标元素 const portalEl = document.createElement('div'); portalEl.id = 'portal'; document.body.appendChild(portalEl); // 组件卸载时移除元素 return () => { document.body.removeChild(portalEl); }; }, []); return <YourModalComponent {...args} />; }; export const Default = Template.bind({});
方法3:用Storybook装饰器全局注入
如果不想修改preview.html,也可以通过装饰器实现全局注入:
- 打开
.storybook/preview.js - 添加全局装饰器:
export const decorators = [ (Story) => { // 检查元素是否已存在,避免重复创建 let portalEl = document.getElementById('portal'); if (!portalEl) { portalEl = document.createElement('div'); portalEl.id = 'portal'; document.body.appendChild(portalEl); } return <Story />; }, ];
这个装饰器会在每个故事渲染前检查并创建元素,确保全局可用。
内容的提问来源于stack exchange,提问作者lcsaloon
相关产品推荐
相关产品推荐

