为什么querySelector无法选中v-for渲染的DOM元素?
问题原因
- 异步数据与时序不匹配
你调用loadFeed的时机是onMounted阶段,此时如果你的ProductFeed列表数据是通过异步接口获取的,接口还没有返回结果,ProductFeed是空数组,v-for自然不会渲染任何.product-item元素。
你用到的nextTick只会等待当前批次同步任务对应的DOM更新完成,不会等待异步接口返回、数据赋值后的DOM更新,所以此时选择对应元素必然返回null。 - 伪类选择器匹配规则问题
:last-of-type伪类的匹配规则是选中同标签名的最后一个元素,而非同class名的最后一个元素。如果.product-feed容器下除了v-for生成的.product-itemdiv之外,还存在其他同标签(div)元素,该选择器匹配到的元素不会带有.product-item类,也会返回null。
解决方案
方法1:调整选择时机,更换更稳妥的选择器
确保在ProductFeed数据赋值完成后,再调用nextTick等待DOM更新,再执行选择逻辑,同时更换匹配逻辑更清晰的选择器:
setup() { const ProductFeed = ref([]) async function loadFeed(){ // 先请求获取列表数据 const res = await fetchProductApi() ProductFeed.value = res.data // 数据赋值后再等待DOM更新 await nextTick(); // 方案A:用last-child匹配父级下的最后一个子元素 let element2 = document.querySelector('.product-item:last-child'); // 方案B:取所有匹配元素的最后一个,逻辑更直观 // let element2 = document.querySelectorAll('.product-item').at(-1) console.log(`element2`, element2) } onMounted(()=> { loadFeed(); }) }
方法2:使用Vue模板引用(更符合Vue开发规范)
避免使用原生DOM选择器的匹配问题,直接通过Vue的ref特性绑定最后一个元素:
<template> <div class="product-feed"> <div v-for="(Product, index) in ProductFeed" :key="Product.ProductID" class="product-item" :ref="el => { if (index === ProductFeed.length - 1) lastProductItem = el }" > <Product-Vue-Component :Product="Product"></Product-Vue-Component> </div> </div> </template> <script setup> import { ref, nextTick } from 'vue' const ProductFeed = ref([]) const lastProductItem = ref(null) async function loadFeed(){ const res = await fetchProductApi() ProductFeed.value = res.data await nextTick() // 直接获取最后一个元素 console.log(lastProductItem.value) } onMounted(()=> { loadFeed(); }) </script>
内容的提问来源于stack exchange,提问作者volume one
相关产品推荐
相关产品推荐

