如何从 v-for 获取和观察对元素的引用?

How to get and observe ref to element from a v-for?

似乎解决类似问题的所有答案都与 Vue 2 相关,或者根本没有给出预期的结果。即使 the docs 中描述的内容也不起作用,因为如果我记录 ref 的值,我只会看到一个空对象。

我有一个这样的模板:

<template>
  <post-content v-for="post in posts" :post-data="post" :key="post.id" ref="lastPost" />
</template>

PostContent 组件的内容并不重要,将其想象成 div 显示 post.content 中的内容。

在脚本中,我从 API 中获取 posts,我希望在引用 lastPost 中加载最后一个 post,这样我可以访问它的HTMLElement(我需要它来做东西,但在这里我只是尝试记录它)。

// This uses composition API with <script setup> syntax

const posts = ref<{id: number, content: string}[]>([])

getPostsFromApi()
  .then((thePost: {id: number, content: string}) => posts.value.push(thePost))

const lastPost = ref<typeof PostContent>()

watch(lastPost, () => nextTick(() => console.log(lastPost.value)), {flush: "post"})

但是,这会导致日志成为一个简单的空对象 {}

为什么记录的是一个空对象,而不是根据文档所期望的?我做错了什么?

与具有常规 <script> 块的 SFC 不同,<script setup> 组件 默认关闭 -- 即 <script setup> 范围内的变量是除非通过 defineExpose() 显式公开,否则不会公开给父级。记录的模板引用中的空对象表示您没有公开任何属性。

要公开 PostContent 的根元素,请在组件中使用模板引用,并使用 [=15= 公开 ref(例如,名为“$el”) ]:

// PostContent.vue
<script setup lang="ts">
const $el = ref()
defineExpose({ $el })
</script>

<template>
  <div ref="$el">...</div>
</template>

顺便说一句,watch(){ flush: 'post' } 可以简化为 watchPostEffect():

watch(lastPost, () => nextTick(() => console.log(lastPost.value.$el)), {flush: "post"})

// OR more simply:
watchPostEffect(() => console.log(lastPost.value.$el))

demo