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

Vue3组件在Storybook中报Cannot read properties of undefined(style)错求助

Vue3 + Storybook DOM操作报错问题

问题详情

我正在使用Vue3结合Storybook进行开发,在组件中编写了如下div_show函数:

function div_show(id) { 
      const elements = document.getElementsByClassName("innerright");
      for (let i = 0; i < elements.length; i++) {
        if (i + 1 != id) {
          elements[i].style.display = "none";
        }
      }
      elements[id - 1].style.display = "block";  
    }

该函数在App.vue中运行完全正常,但在Storybook中使用该组件时,出现错误:Error Cannot read properties of undefined (reading 'style')。

解决方案

原因

Storybook环境下组件的渲染时机、DOM加载状态和App.vue存在差异,调用div_show时可能存在两种情况:

  1. 类名为innerright的DOM元素还未完成挂载,导致elements为空数组
  2. 传入的id值超出了elements的长度范围,使得elements[id-1]为undefined

修复方案

方案1:给DOM操作添加安全校验

直接在原函数中增加存在性判断,避免访问undefined的属性:

function div_show(id) { 
  const elements = document.getElementsByClassName("innerright");
  // 校验id是否在有效范围内
  if (!elements.length || id < 1 || id > elements.length) return;
  
  for (let i = 0; i < elements.length; i++) {
    if (elements[i]) {
      elements[i].style.display = (i + 1 === id) ? "block" : "none";
    }
  }
}

方案2:改用Vue响应式控制(推荐)

直接操作DOM不符合Vue的响应式设计理念,改用响应式数据控制显示更可靠:

  1. 在组件中定义响应式变量:
import { ref } from 'vue';
const activeId = ref(1); // 默认激活第一个元素
  1. 模板中通过响应式数据绑定显示状态:
<div 
  v-for="(item, index) in yourDataList" 
  :key="index + 1" 
  class="innerright"
  :style="{ display: activeId === index + 1 ? 'block' : 'none' }"
>
  <!-- 组件内容 -->
</div>
  1. 修改div_show函数为更新响应式变量:
function div_show(id) {
  activeId.value = id;
}

方案3:确保DOM挂载完成后再调用函数

如果必须保留DOM操作逻辑,需确保组件已挂载完成:

  • 在Vue组件中,将调用逻辑放在onMounted钩子内:
import { onMounted } from 'vue';
onMounted(() => {
  // 这里调用div_show或确保触发div_show的事件在挂载后执行
});
  • 在Storybook的故事文件中,可使用waitFor确保DOM加载完成:
import { waitFor } from '@storybook/testing-library';

export default {
  title: 'YourComponent',
  component: YourComponent,
};

const Template = (args) => ({
  components: { YourComponent },
  setup() {
    return { args };
  },
  template: '<YourComponent v-bind="args" />',
});

export const Default = Template.bind({});
Default.play = async ({ canvasElement }) => {
  await waitFor(() => canvasElement.querySelector('.innerright'));
  // 之后再执行触发div_show的操作
};

内容的提问来源于stack exchange,提问作者Palak Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 08:24:09