本文详解 Vue 3 中使用 ref 获取 DOM 元素并修改其样式,或通过响应式 style 绑定实现安全、可维护的 div 尺寸调整,避免 “Cannot read properties of undefined (reading 'style')” 错误。
本文详解 vue 3 中使用 `ref` 获取 dom 元素并修改其样式,或通过响应式 `style` 绑定实现安全、可维护的 div 尺寸调整,避免 “cannot read properties of undefined (reading 'style')” 错误。
在 Vue 3 中,直接操作 DOM(如 this.$refs.xxx.style)需格外注意生命周期与 ref 的绑定时机。原代码报错 Cannot read properties of undefined (reading 'style') 的根本原因在于:ref="block2" 的元素尚未挂载完成,或 Options API 写法未适配 Vue 3 的 Composition API 主流规范——Vue 3 默认推荐使用 Composition API,且 this.$refs 在 setup() 中不可用,ref 必须通过 ref() 声明并显式返回。
以下提供两种专业、健壮的解决方案,均基于 Composition API,兼容 Vue 3.2+,并支持 CSS 过渡动画:
✅ 方案一:通过 ref 直接操作 DOM(适用于需精细控制样式场景)
<template>
<div ref="container" class="resizable-box"></div>
<input v-model.number="targetSize" type="number" min="50" placeholder="输入宽度/高度(px)" />
<button @click="resizeByRef">按 ref 修改尺寸</button>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const container = ref(null)
const targetSize = ref(100)
const resizeByRef = () => {
if (!container.value) return // 安全防护:确保 DOM 已挂载
container.value.style.width = `${targetSize.value}px`
container.value.style.height = `${targetSize.value}px`
}
// 可选:确保首次渲染后 ref 可用(通常 template 渲染后自动绑定)
onMounted(() => {
console.log('容器已挂载:', container.value)
})
</script>
<style scoped>
.resizable-box {
width: 100px;
height: 100px;
background-color: #7d7d7d;
position: relative;
z-index: 5000;
transition: all 0.3s ease-in;
margin: 16px 0;
}
</style>⚠️ 注意事项:
- 务必添加 if (!container.value) return 防御性检查;
- v-model.number 自动转为数字,避免字符串拼接导致 100px 变成 "100px" → "100pxpx";
- onMounted 确保 DOM 就绪,但实际中 ref 在模板渲染后即有效,此钩子更适用于依赖初始尺寸的逻辑。
✅ 方案二:响应式 :style 绑定(推荐,更 Vue 化、无 DOM 操作风险)
<template>
<div class="resizable-box" :style="boxStyle"></div>
<input v-model.number="targetSize" type="number" min="50" placeholder="输入尺寸(px)" />
<button @click="updateSize">按 style 绑定更新</button>
</template>
<script setup>
import { ref, computed } from 'vue'
const targetSize = ref(100)
const boxStyle = computed(() => ({
width: `${targetSize.value}px`,
height: `${targetSize.value}px`,
backgroundColor: '#7d7d7d',
position: 'relative',
zIndex: 5000,
transition: 'all 0.3s ease-in',
margin: '16px 0'
}))
const updateSize = () => {
// 无需手动操作 DOM,仅更新响应式数据,视图自动同步
}
</script>该方案完全规避 DOM 访问,利用 Vue 的响应式系统驱动样式更新,语义清晰、可测试性强,且天然支持服务端渲染(SSR)与单元测试。
立即学习“前端免费学习笔记(深入)”;
? 关键总结
- ❌ 错误写法根源:Vue 3 Options API 中 this.$refs 不再默认可用;ref="xxx" 在 setup() 中必须用 ref(null) 声明并 return;未校验 ref 是否为空。
- ✅ 最佳实践:优先选用 :style 响应式绑定(方案二),简洁、安全、符合 Vue 响应式哲学;仅当需调用原生 DOM 方法(如 focus()、scrollIntoView())时才用 ref 操作(方案一)。
- ? 样式增强:CSS transition 属性需写在基础类(.resizable-box)中,而非内联 :style,否则过渡可能失效(因内联样式优先级高,会覆盖 CSS 类中的 transition)。
两种方案均支持平滑动画、输入校验与错误防御,开发者可根据项目规范与具体需求灵活选择。

















