动态模块赋值问题:为何无法获取priceElement组件高度?
问题原因分析
1. 动态ref绑定逻辑错误
你在watch回调里创建的tempObject[keyRef-${i}]是局部ref变量,Vue无法将动态生成的priceElement组件实例关联到这些局部ref上。Vue中v-for的动态ref需要通过数组或回调函数接收,而非这种动态命名的独立ref——你写的:ref="keyRef-${index}",Vue会去组件setup上下文里找keyRef-0、keyRef-1这类变量,但这些变量只存在于循环的临时对象中,根本不在组件上下文里,所以ref始终为null,useElementSize自然拿不到元素尺寸。
2. 数据更新与DOM渲染时机不匹配
当你在watch(priceWrapHeight)回调里修改priceWrapElements时,Vue会触发v-for重新渲染,但这个过程是异步的。而你在循环里直接给tempObject绑定useElementSize,此时对应的priceElement还没渲染到DOM中,传入useElementSize的是空ref,后续DOM渲染完成后也不会自动关联,因此无法监听尺寸变化。
当前结构下的可行实现方案
可以实现,核心是修正动态ref的绑定方式,同时等待DOM渲染完成后再初始化尺寸监听:
<template> <ul class="priceWrap" ref="priceWrap"> <priceElement class="priceElement" v-for="(item, index) in priceWrapElements" :item="item" :index="index" :key="item.someKey" :ref="el => { if (el) priceElementRefs[index] = el }" > {{ Number(item.priceElementText).toFixed(5) }} </priceElement> </ul> </template> <script setup> const store = useStore() const priceWrapElements = ref([]) const count = 4 const priceWrap = ref(null) const priceWrapSizes = useElementSize(priceWrap) // 修正原代码的变量名笔误 const priceWrapHeight = computed(() => priceWrapSizes.value.height) // 用数组存储动态生成的priceElement的ref const priceElementRefs = ref([]) // 存储每个元素的尺寸监听结果 const priceElementSizes = ref([]) watch(priceWrapHeight, async (currentValue) => { // 清空旧数据 priceWrapElements.value = [] priceElementRefs.value = [] priceElementSizes.value = [] // 生成列表数据 for (let i = 0; i < count; i++) { priceWrapElements.value.push({ someKey: `someValue-${i}`, priceElementText: '12' + i }) } // 等待DOM渲染完成,确保priceElementRefs被填充真实实例 await nextTick() // 为每个已渲染的元素初始化尺寸监听 priceElementRefs.value.forEach((el, index) => { if (el) { priceElementSizes.value[index] = useElementSize(ref(el)) } }) }) </script>
关键修正点
- 改用回调式ref
:ref="el => { if (el) priceElementRefs[index] = el }",将动态生成的priceElement实例存入数组priceElementRefs,确保Vue能正确绑定ref。 - 修正原代码中
priceWrapSize的变量名笔误,改为priceWrapSizes。 - 更新
priceWrapElements后,用await nextTick()等待DOM渲染完成,再初始化useElementSize,此时ref已指向真实组件实例。 - 将每个元素的尺寸监听结果存入
priceElementSizes数组,方便后续调用。
内容的提问来源于stack exchange,提问作者Mikhail Krivosheev
相关产品推荐
相关产品推荐

