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

Vue项目$ref报错:Cannot read properties of null (reading 'style')

解决Vue中"Cannot read properties of null (reading 'style')"报错

报错原因

  1. 组件挂载前获取DOM无效:script顶部直接用document.querySelector查询DOM时,组件模板还未渲染到页面,返回结果为null,后续操作style属性自然报错。
  2. ref引用时机错误:在组件导出外部使用this.$refs.secHand,此时this并非Vue实例,无法拿到正确的DOM引用。
  3. 定时器中this指向异常:直接用setInterval(setDate, 1000)调用函数,setDate内的this指向window而非Vue实例,导致this.secHand不存在。
  4. 未正确使用组件数据:代码中selectValue未定义,应该使用组件data中的selectedHour,且需处理类型转换问题。

修复方案及代码

将DOM操作、定时器逻辑移至Vue生命周期钩子中,确保在组件挂载后执行,并正确使用Vue实例的上下文:

<template>
  <div class="clock">
    <div class="clock-face">
      <div class="hand secHand" ref="secHand"></div>
      <div class="hand minHand" ref="minHand"></div>
      <div class="hand hourHand" ref="hourHand"></div>
      <div class="circle"></div>
    </div>
    <select
      name="box-1"
      id="select"
      @change="updateClock"
      v-model="selectedHour"
    >
      <option class="option" value="0">0 UTC</option>
      <option class="option" value="1">+1 UTC</option>
      <option class="option" value="2">+2 UTC</option>
      <option class="option" value="3">+3 UTC</option>
      <option class="option" value="4">+4 UTC</option>
      <option class="option" value="5">+5 UTC</option>
      <option class="option" value="6">+6 UTC</option>
      <option class="option" value="7">+7 UTC</option>
      <option class="option" value="8">+8 UTC</option>
      <option class="option" value="9">+9 UTC</option>
      <option class="option" value="10">+10 UTC</option>
      <option class="option" value="11">+11 UTC</option>
    </select>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      selectedHour: "0",
      timer: null
    };
  },
  mounted() {
    // 组件挂载后启动定时器,箭头函数保证this指向Vue实例
    this.timer = setInterval(() => this.setDate(), 1000);
    // 初始化时立即执行一次时钟更新
    this.setDate();
  },
  beforeUnmount() {
    // 组件卸载前清除定时器,避免内存泄漏
    clearInterval(this.timer);
  },
  methods: {
    setDate() {
      const now = new Date();
      // 通过$refs获取DOM元素
      const secHand = this.$refs.secHand;
      const minHand = this.$refs.minHand;
      const hourHand = this.$refs.hourHand;

      // 计算秒针角度并更新样式
      const seconds = now.getSeconds();
      const secondsDegrees = (seconds / 60) * 360 + 90;
      secHand.style.transform = `rotate(${secondsDegrees}deg)`;
      secHand.style.transition = secondsDegrees === 90 ? "none" : "all 0.05s cubic-bezier(0.1, 2.7, 0.58, 1)";

      // 计算分针角度并更新样式
      const minutes = now.getMinutes();
      const minutesDegrees = (minutes / 60) * 360 + 90;
      minHand.style.transform = `rotate(${minutesDegrees}deg)`;

      // 计算时针角度并更新样式
      const hours = now.getHours();
      const newHour = (hours + Number(this.selectedHour)) % 24;
      const hoursDegrees = (newHour / 12) * 360 + 90;
      hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
    },
    updateClock() {
      // 切换时区时立即更新时钟
      this.setDate();
    }
  }
};
</script>

关键修复点

  • 将setDate作为组件方法,确保内部this指向Vue实例。
  • 在mounted钩子中执行DOM操作和定时器启动,此时组件已完成挂载,$refs能正确获取DOM元素。
  • 使用beforeUnmount清除定时器,避免内存泄漏。
  • 修正事件名@Change为@change(Vue事件名需小写),添加时区切换时的即时更新逻辑。
  • 将selectedHour转为数字后计算,避免字符串拼接导致的逻辑错误,同时处理小时数超过24的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 09:45:06