我想对通过循环v-for
遍历任意对象集合创建的模板引用元素数组所做的更改做出反应。我想将此数组传递给组件/可组合项并让其对更改做出反应。
文档提供了一种将这些元素保存到数组的方法:https://vuejs.org/guide/essentials/template-refs.html#refs-inside-v-for
我修改了提供的示例,以查看生成的itemsRef
数组是否具有响应性。代码如下:
<script setup>
import { ref, useTemplateRef, watch, markRaw } from 'vue'
const list = ref([1, 2, 3])
const itemRefs = useTemplateRef('items')
watch(itemRefs, () => {
console.log("itemsRef:", itemRefs.value.length);
}, {deep: true});
watch(list, () => {
console.log("list:", list.value.length, itemRefs.value.length);
}, { deep: true });
</script>
<template>
<button @click="list.push(list.length + 1)">add</button>
<ul>
<li v-for="item in list" ref="items">
{{ item }}
</li>
</ul>
</template>
但从其 TypeScript 签名来看,的返回值useTemplateRef
似乎是:ShallowRef
function useTemplateRef<T>(key: string): Readonly<ShallowRef<T | null>>
因此watch
实际上itemRefs
只运行一次:
如您所见,数组的内容正在发生变化(已更新),但vue 未捕获到list
这些变化。我尝试进行深度处理,但没有帮助。itemRefs
watch
有没有办法让 ref 不那么浅?或者还有其他方法?
const { createApp, ref, useTemplateRef, watch, markRaw } = Vue;
const app = createApp({
setup() {
const list = ref([1, 2, 3]);
const itemRefs = useTemplateRef('items');
watch(itemRefs, () => {
console.log("itemsRef: ", itemRefs.value.length);
}, { deep: true });
watch(list, () => {
console.log("list: ", list.value.length, itemRefs.value.length);
}, { deep: true });
return { list }
}
});
app.mount('#app');
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="app">
<button @click="list.push(list.length + 1)">add</button>
<ul>
<li v-for="item in list" ref="items">
{{ item }}
</li>
</ul>
</div>
itemRefs
已更新(例如,响应式)。但它始终在list
更改后 1 个渲染周期内更新。包装你的
console.log
(nextTick
从'vue'导入)并且数字将匹配:另请注意,由于它是浅层引用,因此您无法对其进行深度监视。为了能够获得此功能,请使用普通的
ref
:根据 vue 的文档,在 a 内部使用
const elements = ref([])
with并不能保证顺序。ref="elements"
v-for
此外,如果您
ref="elements"
是一个组件,那么elements
数组将充满ComponentPublicInstance
元素。为了解决这个问题,我使用这个要点作为基础并创建了这个可组合项:
可以这样使用:
现在
messageRefs
数组已完全反应并与数组完全同步messages
。