VueJS中v-for渲染后,getElementsByClassName无法遍历元素的问题
问题排查与解决方案
核心问题原因
你代码里的关键问题是没有等待所有文章请求完成就执行DOM遍历:
mounted钩子中,await this.getCategories()仅等待分类接口返回,但后续forEach循环里的getPosts是异步操作,你通过then回调向tutos数组push数据,这部分逻辑没有被await等待。- 当你调用
await this.$nextTick()时,tutos数组还未被全部填充,对应的DOM元素自然还没渲染出来。 - 控制台打印的
HTMLCollection是动态集合,它会实时反映DOM状态,所以你看到的是后续DOM更新后的状态,但代码执行Array.from(tutos_list)时,集合里实际没有元素,导致forEach无输出。
修复方案
方案1:用Promise.all等待所有异步请求完成后更新数据
重构数据获取逻辑,确保所有文章请求完成后再一次性更新 tutos 数组,这样DOM就能完整渲染:
<template> <div id="tutos"> <div v-for="(tuto, index) in tutos" :id="tuto.categorie_slug" :key="index" class="row" > <div class="tutos-list"></div> </div> </div> </template> <script> export default { name: "Tutos", data() { return { tutos: [], }; }, methods: { async getCategories() { const categories = await this.axios.get("/categories"); return categories.data; }, async getPosts(id) { const posts = await this.axios.get(`/posts?categories=${id}`); return posts.data; }, }, async mounted() { // 1. 获取分类 const categories = await this.getCategories(); // 2. 收集所有需要执行的文章请求Promise const postPromises = categories .filter(categorie => categorie.count > 0) .map(async categorie => { const posts = await this.getPosts(categorie.id); return { categorie_name: categorie.name, categorie_slug: categorie.slug, posts: posts, }; }); // 3. 等待所有文章请求完成,一次性更新tutos this.tutos = await Promise.all(postPromises); // 4. 等待DOM渲染完成后遍历元素 await this.$nextTick(); const tutos_list = document.getElementsByClassName("tutos-list"); Array.from(tutos_list).forEach((list) => { console.log(list); }); }, }; </script>
方案2:用watch监听tutos数组变化(更符合Vue风格)
避免在mounted里直接等待异步操作,而是通过watch监听tutos数组的变化,当数组完全更新后再处理DOM:
<template> <div id="tutos"> <div v-for="(tuto, index) in tutos" :id="tuto.categorie_slug" :key="index" class="row" > <div class="tutos-list"></div> </div> </div> </template> <script> export default { name: "Tutos", data() { return { tutos: [], }; }, methods: { async getCategories() { const categories = await this.axios.get("/categories"); return categories.data; }, async getPosts(id) { const posts = await this.axios.get(`/posts?categories=${id}`); return posts.data; }, }, watch: { tutos: { deep: true, async handler(newVal) { // 确保数组有数据后再执行 if (newVal.length === 0) return; await this.$nextTick(); const tutos_list = document.getElementsByClassName("tutos-list"); Array.from(tutos_list).forEach((list) => { console.log(list); }); } } }, async mounted() { const categories = await this.getCategories(); const postPromises = categories .filter(categorie => categorie.count > 0) .map(async categorie => { const posts = await this.getPosts(categorie.id); return { categorie_name: categorie.name, categorie_slug: categorie.slug, posts: posts, }; }); this.tutos = await Promise.all(postPromises); }, }; </script>
额外说明
- 尽量避免直接操作DOM,Vue的核心是数据驱动视图,如果需要操作DOM元素,优先考虑使用ref来获取元素,而非
getElementsByClassName。 - 不要混用
await和then,保持异步代码风格统一,提升可读性。
内容的提问来源于stack exchange,提问作者To Bear
相关产品推荐
相关产品推荐

