You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Storybook报错Target container is not a DOM element:React模态框DOM适配方法

解决Storybook中React模态框Portal目标元素缺失问题

方法1:全局添加目标DOM元素(推荐)

直接修改Storybook的根模板文件,让所有故事页面都包含#portal元素:

  1. 找到项目中的.storybook/preview.html文件(如果没有就新建一个)
  2. 在<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,也可以通过装饰器实现全局注入:

  1. 打开.storybook/preview.js
  2. 添加全局装饰器:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:56:50