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

Vue/Nuxt中如何优先获取模板DOM宽度并正确传递给子组件

问题原因

你当前的实现存在3个核心问题:

  • width未在data中声明,不属于响应式变量,赋值后不会触发子组件props更新
  • 宽度获取逻辑仅放在updated钩子中,子组件首次渲染时大概率还没完成宽度计算,会拿到undefined触发类型报错
  • 没有做ref存在性校验,DOM未完全挂载时访问$refs.demandContainer.$el会直接抛出异常
解决方案

按照以下步骤修改即可:

  1. 父组件声明响应式的width变量,抽离公共宽度获取方法,在合适的生命周期触发计算
  2. 新增窗口resize监听保证宽度实时更新,同时做好边界校验避免报错
  3. 子组件可选增加宽度校验逻辑,避免空值渲染异常

父组件修改后代码

<template>
  <v-col cols="12" sm="12" md="4" ref="demandContainer">
    <div class="chart-container p-4 dark-background">
      <div class="font-weight-bold">Demand</div>
      <area-chart
        v-if="trendsData.length > 0"
        :data="trendsData"
        :baseWidth="width"
      >
      </area-chart>
    </div>
  </v-col>
</template>

<script>
export default {
  data() {
    return {
      // 声明响应式宽度变量,初始值设为0避免子组件接收到undefined
      width: 0,
      trendsData: []
    }
  },
  mounted() {
    // 组件挂载后等DOM完全渲染再获取宽度
    this.$nextTick(() => {
      this.getContainerWidth()
    })
    // 监听窗口大小变化,实时更新宽度
    window.addEventListener('resize', this.getContainerWidth)
  },
  beforeDestroy() {
    // 组件销毁前移除监听,避免内存泄漏
    window.removeEventListener('resize', this.getContainerWidth)
  },
  updated() {
    // 组件更新后重新校验宽度
    this.$nextTick(() => {
      this.getContainerWidth()
    })
  },
  methods: {
    getContainerWidth() {
      // 先判断ref是否存在,避免DOM未渲染时报错
      if (!this.$refs.demandContainer) return
      const newWidth = this.$refs.demandContainer.$el.clientWidth
      // 仅宽度真实变化时才赋值,减少不必要的组件更新
      if (newWidth !== this.width) {
        this.width = newWidth
      }
    },
    // 你的trendsData获取方法,拿到数据后额外触发一次宽度计算
    async fetchTrendsData() {
      // 此处替换为你的实际接口请求逻辑
      this.trendsData = await request.get('/your/api/path')
      this.$nextTick(() => {
        this.getContainerWidth()
      })
    }
  }
}
</script>

子组件可选优化

如果仍存在渲染异常,可在子组件增加宽度判断或监听逻辑:

<!-- 模板增加v-if判断,宽度有效时才渲染svg -->
<svg v-if="baseWidth > 0" ref="svg-area" :width="baseWidth" :height="baseHeight">
</svg>

<script>
export default {
  props: {
    baseWidth: {
      type: Number,
      default: 0
    },
    baseHeight: {
      type: Number,
      default: 300
    }
  },
  watch: {
    // 若宽度变化后需要重绘图表,可在此处添加对应逻辑
    baseWidth(newVal) {
      if (newVal > 0) {
        // 你的图表重绘逻辑
      }
    }
  }
}
</script>
补充说明

如果是Nuxt服务端渲染场景,所有DOM相关操作都放在mounted钩子中执行即可,服务端不会执行该钩子,不会出现DOM找不到的报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 08:57:01