You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 13:50:20