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

使用Vuefire在组件渲染前加载Firestore数据遇异常

问题:Firestore加载用户姓名正常,但Firebase Storage头像无法显示

我需要实现一个人员表格,展示用户姓名与头像:姓名数据来自Firestore数据库,头像通过姓名匹配Firebase Storage中的对应图片。尝试过多种代码组合均未成功,当前代码错误最少,可正常填充表格中的姓名,但头像无法加载,其值从占位图地址变为undefined。

原本认为需要用<Suspense>包裹PlayerRow组件(因为使用了storageRef与useStorageFileUrl方法),但引入后反而出现更多问题。根据Vuefire文档及代码定义,这些方法并非异步,但直接调用无法得到有效结果。


GamePlanner.vue

<template>
    <div>
    <Field />
    <Bench />
    <!-- <Suspense>
        <template #default> -->
            <PlanSummary />
        <!-- </template>
        <template #fallback>
            <div class="loading">Loading...</div>
        </template>
    </Suspense> -->
    </div>
</template>

PlanSummary.vue

<template>
    <div class="summaryContainer">
        <div class="inningTableContainer">
            <table class="inningTable">
                <tbody>
                    <!-- <Suspense> -->
                        <!-- <template #default> -->
                            <PlayerRow v-for="player in players.value" :key="player.id" :player="(player as Player)" />
                        <!-- </template> -->

                        <!-- <template #fallback>
                            <tr data-playerid="0">
                                <img class="playerImage" src="https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50" />
                                Loading players...
                                <span class="playerNumber">00</span>
                            </tr>
                        </template> -->
                    <!-- </Suspense> -->
                </tbody>
            </table>
        </div>

    </div>
</template>

<script setup lang="ts">
import { computed, onErrorCaptured, ref } from "vue";
import { useFirestore, useCollection } from "vuefire";
import { collection } from "firebase/firestore";
import { Player, Inning } from "@/definitions/GamePlanner";
import PlayerRow from "./PlayerRow.vue";

const db = useFirestore();
const gamePlanID = "O278vlB9Xx39vkZvIsdP";

// const players = useCollection(collection(db, `/gameplans/${gamePlanID}/participants`));

// const players = ref(useCollection(collection(db, `/gameplans/${gamePlanID}/participants`)));

// Unhandled error during execution of scheduler flush
// Uncaught (in promise) DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
const players = ref(); 
players.value = useCollection(collection(db, `/gameplans/${gamePlanID}/participants`));

// Seeminly infinite loop with "onServerPrefetch is called when there is no active component instance to be associated with."
// Renders 5 (??) undefined players
// One error shown: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'substring')
// const players = computed(() => useCollection(collection(db, `/gameplans/${gamePlanID}/participants`)));

// onErrorCaptured((error, vm, info) => {
//     console.log("Error loading Summary component: ", error, "vm: ", vm, "info: ", info);
//     throw error;
// });
</script>

PlayerRow.vue

<template>
    <tr :key="player2.id" :data-playerid="player2.id">
        <td>
            <img class="playerImage" :src="playerPictureURL" />
            {{ player2.nickname || player2.firstName + " " + player2.lastName }}
            <span class="playerNumber">{{ player2.playerNumber }}</span>
        </td>
    </tr>
</template>

<script lang="ts" setup>
import { ref, PropType, computed, onMounted, watch } from "vue";
import { useFirebaseStorage, useStorageFileUrl } from "vuefire";
import { ref as storageRef } from 'firebase/storage';
import { Player, Inning } from "@/definitions/GamePlanner";

const fs = useFirebaseStorage();
const props = defineProps({
    'player': { type: Object as PropType<Player>, required: true },
    // 'innings': Array<Inning>
});
const player2 = ref(props.player);

// const innings = computed(() => props.innings);

// const playerPictureURL = computed(() => {
//     const playerPictureFilename = `${player2.value.firstName.substring(0,1)}${player2.value.lastName}.png`.toLowerCase();
//     const playerPictureResource = storageRef(fs, `playerPictures/${playerPictureFilename}`);
//     return useStorageFileUrl(playerPictureResource).url.value as string;
// });
// const playerPictureURL = ref(() => {
//     const playerPictureFilename = `${player2.value.firstName.substring(0,1)}${player2.value.lastName}.png`.toLowerCase();
//     const playerPictureResource = storageRef(fs, `playerPictures/${playerPictureFilename}`);
//     return useStorageFileUrl(playerPictureResource).url.value as string;
// });

const playerPictureURL = ref("https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50");
async function getPlayerPictureURL() {
    console.log("PlayerRow.ts getPlayerPictureURL");
    const playerPictureFilename = `${player2.value.firstName.substring(0,1)}${player2.value.lastName}.png`.toLowerCase();
    const playerPictureResource = await storageRef(fs, `playerPictures/${playerPictureFilename}`);
    playerPictureURL.value = await useStorageFileUrl(playerPictureResource).url.value as string;
}
onMounted(() => {
    console.log("PlayerRow.ts onMounted");
    getPlayerPictureURL();
});
watch(playerPictureURL, (newVal, oldVal) => {
    console.log("PlayerRow.ts watch playerPictureURL");
    console.log("newVal: " + newVal);
    console.log("oldVal: " + oldVal);
});
</script>

相关依赖版本

{
    "vue": "^3.2.45",
    "firebase": "^9.15.0",
    "typescript": "^4.9.3",
    "vite": "^4.0.0",
    "vue-router": "^4.1.6",
    "vue-tsc": "^1.0.11",
    "vuefire": "3.0.0-beta.6"
}

内容的提问来源于stack exchange,提问作者Rawrcasm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 12:05:14