【问题标题】:Vue component being loaded before calling router.push()在调用 router.push() 之前加载 Vue 组件
【发布时间】:2020-02-23 13:18:24
【问题描述】:

我正在使用 Vue js 和 Firestore 为 2 名玩家开发一款在线游戏。

点击新游戏按钮时;

  • 我创建了一个新房间并将其保存在数据库中。
  • 我使用 firestore docChanges () 函数检查更改。如果创建了新房间,我会将当前玩家和对手重定向到 Game.vue 页面。

我的代码

Home.vue

import db from "@/firebase/init";
import Navbar from "@/components/Navbar";
export default {
  name: "Home",
  components: {
    Navbar
  },
  data() {
    return {
   
    };
  },

  methods: {

    newGame() {
      this.createGameRoom();
    },
    createGameRoom() {
      let gameNo = Date.now();
      db.collection("game_rooms")
        .add({
          gameNo: gameNo,
        })
        .then(() => {
          this.createGameAndOpponent();
        });
    },

    createGameAndOpponent() {
      db.collection("game_rooms").onSnapshot(snapshot => {
        snapshot.docChanges().forEach(change => {
          if (change.type == "added") {

           console.log("******************************")
           console.log('Current Page Name(Static):Home.vue')
           console.log('Current Page Name(Dynamic):'+this.$route.name)
           console.log("Pushing to game component")
           console.log("******************************")
            this.$router.push("/game");
          }
        });
      });
    },
  }
};
<template>
  <div id="home">
    <Navbar />
    <div class="home container">
      <div class="card">
        <a class="waves-effect waves-light btn-large btn deep-purple darken-1" @click="newGame">
         New Game
        </a>
      </div>
    </div>
  </div>
</template>

Game.vue

export default {
  name: "Game",
  data() {
    return {};
  },
  created() {
    console.log("******************************");
    console.log("Current Page Name(Static):Game.vue");
    console.log("Current Page Name(Dynamic):" + this.$route.name);
    console.log("Game component created");
  },

  methods: {}
};
<template>
  <div id="game">
    <router-link
      :to="{name:'Home'}"
    >Return Home Page</router-link>
  </div>
</template>

Vue 路由器 - index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Game from '../views/Game.vue'
Vue.use(VueRouter)


const routes = [{
    path: '/',
    name: 'Home',
    component: Home,

}, {
    path: '/game',
    name: 'Game',
    component: Game,

}, ]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})


export default router

我正在检查 createGameAndOpponent 函数内部:

如果“game_rooms”发生变化或创建了新游戏,请从在线用户中找到对手并将两个用户重定向到游戏页面。但是这里重定向的时候出错了。页面未重定向并出现以下错误。

但我收到以下错误

未捕获(承诺)
NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated", message: "导航到当前位置 ("/game") 是不允许的"

虽然当前页面是Home.vue,但是说当前页面是game.vue,并说“不允许进入'/game'页面”。

我做了以下来了解问题的详细信息。

  • 当我点击 Home.vue 中的“New Game”按钮时,在进入 Game 页面之前,我用控制台静态和动态地打印了当前页面的名称。
  • 在Game.vue页面中,在created()方法中创建Game.vue组件时,我用控制台静态和动态打印了页面名称。

如图所示,虽然Active页面是Home.vue this.$route.name显示的是游戏页面的名称。

我在 firestore docChanges() 函数中重定向到 game.vue。问题应该在这里。 但我无法解决问题的根源。

我该如何解决这个问题?

注意事项:

【问题讨论】:

  • 是不是因为你做了querySnapshot.docChanges().forEach()所以可能会重定向多次?如果您在第一个 change.type == "added" 之后中断会发生什么?您需要使用另一种方法循环才能做到这一点,请参阅stackoverflow.com/questions/60260237/…
  • 为了让问题细节不会太长,我删除了所有不必要的代码。如果数据库中的玩家中有活跃玩家,我定向到 game.vue 页面。我正在审查您共享的资源。 @RenaudTarnec
  • 我的意思是你可以在你的forEach循环中多次重定向到/game
  • 我检查了您分享的来源。我用“Break”解决了这个问题。但是游戏是实时的,所以我使用了“docChanges”方法。为两个用户控制和引导。但在这个来源中,只有活动用户正在重定向。有没有办法停止 Foreach? @RenaudTarnec

标签: javascript firebase vue.js google-cloud-firestore vue-router


【解决方案1】:

在我看来,你似乎有两个问题。

你能确定下面的代码只调用一次吗?你使用一个forEach,可能会被this.$router.push 调用两次。您的日志显示了回调已被调用两次的逻辑。

        snapshot.docChanges().forEach(change => {
      if (change.type == "added") {

       console.log("******************************")
       console.log('Current Page Name(Static):Home.vue')
       console.log('Current Page Name(Dynamic):'+this.$route.name)
       console.log("Pushing to game component")
       console.log("******************************")
        this.$router.push("/game");
      }
    });

如果是这样,您可能不需要 forEach 而是一个简单的 forreturn,或者在您尝试 break 循环调用时使用带有 return true 的 [].some

【讨论】:

  • 我试过你说的方法,但还是报同样的错误。
  • @HibritUsta 休息没问题。但是你也应该在 vue 组件 destroy.like 上取消绑定事件: beforeDestroy() { unconnectYourFireBase() }
  • 对不起。我无法完全理解你所说的。你能更详细地解释或说明你的意思吗? @iulo
【解决方案2】:

根据您的问题,根据我们的 cmets,问题似乎来自您在以下循环中多次重定向(使用 this.$router.push("/game");):

createGameAndOpponent() {
  db.collection("game_rooms").onSnapshot(snapshot => {
    snapshot.docChanges().forEach(change => {
      if (change.type == "added") {
        //...
        this.$router.push("/game");
      }
    });
  });
}

您应该在第一次遇到等于addedchange.type 时中断循环。由于docChanges()返回一个数组,你可以这样做:

createGameAndOpponent() {
  db.collection("game_rooms").onSnapshot(snapshot => {
    for (const change of snapshot.docChanges()) {
      if (change.type == "added") {
        this.$router.push("/game");
        break;
      }
    });
  });
}

注意以下几点:

  1. 由于通过 db.collection("game_rooms").onSnapshot 设置监听器,您应该从 vue.js 的 created 钩子中调用此方法(仅一次)。
  2. 另一方面,在getGameUsers() 方法中,由于您只查询一次Firestore 数据库(如果我没记错的话),最好使用get() 方法,它只查询一次数据库。

【讨论】:

  • 我尝试了你说的解决方法,但它也给出了类似问题的错误。我发布了项目以便更好地查看问题:link。您可以使用示例用户注册和登录。
  • 我刚刚尝试了一个示例用户,现在console.logs 似乎是正确的。 IE。 console.log('Current Page Name(Static)...)console.log('Current Page Name(Dynamic):...) 匹配
  • 第一次点击看是正确的。但是当你回到首页再次点击新游戏按钮时,它会报错。
  • 如果没有Minimal, Reproducible Example,恐怕很难进一步帮助您。您的代码非常复杂和丰富,如果不复制您的整个应用程序,几乎不可能提供更多帮助(即使来自您在上面共享的应用程序的构建实例)。
猜你喜欢
  • 1970-01-01
  • 2018-11-29
  • 2019-01-03
  • 2021-12-09
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 2019-12-12
  • 1970-01-01
相关资源
最近更新 更多