Vue项目$ref报错:Cannot read properties of null (reading 'style')
解决Vue中"Cannot read properties of null (reading 'style')"报错
报错原因
- 组件挂载前获取DOM无效:script顶部直接用
document.querySelector查询DOM时,组件模板还未渲染到页面,返回结果为null,后续操作style属性自然报错。 - ref引用时机错误:在组件导出外部使用
this.$refs.secHand,此时this并非Vue实例,无法拿到正确的DOM引用。 - 定时器中this指向异常:直接用
setInterval(setDate, 1000)调用函数,setDate内的this指向window而非Vue实例,导致this.secHand不存在。 - 未正确使用组件数据:代码中
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
相关产品推荐
相关产品推荐

