首次加载页面时未定义Vue.prototype

时间:2020-03-27 13:14:17

标签: javascript vue.js vuejs2 vue-router

因此,我正在尝试在main.js文件中向axios发出请求。

如图所示,我正在使用vue-router在加载每个组件之前发出此请求。但是,当我的网页首次加载时,我无法使其正常工作。我的意思是,axios请求在组件加载后完成。然后,这将失败:

mounted() {
    if (Vue.prototype.$user.role == "Owner") {
      this.isOwner = true;
      this.estancoId = Vue.prototype.$user.estanco;
    }
  },

它在控制台日志上显示此错误:

[Vue warn]: Error in mounted hook: "TypeError: Cannot read property 'role' of undefined"

found in

---> <Header> at src/components/Header.vue
       <App> at src/App.vue
         <Root>

我尝试通过异步/等待发出此请求,我尝试了方法mounted(), created(), beforeMount(), beforeCreate(),但仍然相同。我是Vue.js的新手,我被困在这里,不知道该怎么办。

编辑整个文件以查看应用程序结构: main.js

import router from './router'
import Vue from 'vue'
import App from './App.vue'
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import axios from 'axios'
import Vuex from 'vuex'

// Install BootstrapVue
import 'leaflet/dist/leaflet.css';

Vue.use(BootstrapVue)
// Optionally install the BootstrapVue icon components plugin
Vue.use(IconsPlugin)
Vue.use(axios)
Vue.use(Vuex)
Vue.config.productionTip = false

const store = new Vuex.Store({
  state: {
    user : {}
  },
  mutations : {
    set_user (state,user) {
      state.user = user
    }
  }
})

export default store

/* eslint-disable */
router.beforeEach((to, from, next) => {
  if (from.path.indexOf("modificarCatalogo") == -1 && to.path.indexOf("modificarCatalogo") == -1) {
    localStorage.removeItem("catalogue");
  }
  if (localStorage.getItem("token") != null) {
    axios
      .get(`${process.env.VUE_APP_API_BASE_URL}/user/role`, {
        headers: {
          Authorization: "Token " + localStorage.getItem("token")
        }
      })
      .then(response => {
        store.commit('set_user', response.data);
        console.log("First then")
        console.log(store.state.user)
      }).catch(function (error) {
         // handle error case here
         console.log(error);

      }).then(function () {
         // always executed
         console.log("Second then")
         next();
      });
     }else{
        next();
     }
});
/* eslint-enable */

Vue.use(router)

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

现在有了Vuex,因为我尝试了@ellisdod答案,但

App.vue

<template>
  <div>
    <Header />
    <router-view />
    <Footer />
  </div>
</template>

然后,在 Header.vue 中,我在这里调用Vuex $ store,但这是相同的。我需要在所有地方都完成此操作,因此我尝试在App.vue中调用该方法,但仍然没有结果,它现在使用Vuex的解决方案返回一个空对象,但是只是一个空对象,而不包含用户数据。

export default {
  name: "Header",
  data() {
    return {
      token: localStorage.getItem("token"),
      isOwner: "",
      estancoId: ""
    };
  },
  mounted() {
    console.log("Header log")
    if (this.$store.state.user.role == "Owner") {
      this.isOwner = true;
      this.estancoId = this.$store.state.user.estanco;
    }
  },

其余部分与我认为无关

2 个答案:

答案 0 :(得分:0)

如果使用Vuex存储用户数据,则可以用空对象预填充用户值,这样它就不会引发错误。

const store = new Vuex.Store({
  state: {
    user : {}
  },
  mutations : {
    set_user (state,user) {
      state.user = user
    }
  },
  actions : {
    loadUserFromLocal ({commit,state}) {
      if (localStorage.getItem("token") === null) return null
      return axios
        .get(`${process.env.VUE_APP_API_BASE_URL}/user/role`, {
        headers: {
          Authorization: "Token " + localStorage.getItem("token")
        }
      })
      .then(response => {
        commit('set_user', response.data);
        console.log("First then")
        console.log(state.user)
      }).catch(function (error) {
         // handle error case here
         console.log(error);
      })

    }
  }
})

new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app')

然后在安装的主App组件的挂钩中添加:

mounted () {
    this.$store.dispatch('loadUserFromLocal')
  }

现在在您的路由器中,而不是在每条路由之前发出服务器请求,您只需检查商店即可:

if (this.$store.state.user.role) {
  // handle logged in user
}

答案 1 :(得分:-1)

嗨,

基于问题编辑,评论和答案的完整答案:

问题

Vue-router的beforeEach方法将仅在路由中定义的组件中执行。
就您而言,

  1. beforeEach不会在 Header 组件中调用,因为它不是路由的一部分。它是一个独立的组件。
    因此,您无法访问其中的(100, 5)

store.js

$user

@ellisdod-谢谢。

现在,您可以使用组件中存储的用户变量,并且在完成数据提取时将对其进行更新,或者将显示初始值直到该时间为止

因此无需在router.beforeEach中获取数据

router.js

    import axios from 'axios'
    import Vuex from 'vuex'

    const store = new Vuex.Store({
    state: {
      user : {}
    },
    mutations : {
      set_user (state,user) {
        state.user = user
      }
    }
    actions : {
        loadUserFromLocal ({commit,state}) {
          if (localStorage.getItem("token") === null) return null
          return axios
            .get(`${process.env.VUE_APP_API_BASE_URL}/user/role`, {
            headers: {
              Authorization: "Token " + localStorage.getItem("token")
            }
          })
          .then(response => {
            commit('set_user', response.data);
            console.log("First then")
            console.log(state.user)
          }).catch(function (error) {
             // handle error case here
             console.log(error);
          })

        }
      }
    })
    export default store

正如您在vue-router中所知道的,如果调用next,则认为导航已确认,并且组件将被渲染。
有关在 // --> all imports import store from './store' // --> added // --> all routes to be defined here... router.beforeEach((to, from, next) => { // --> other logic for filtering routes // --> you can use 'store' variable here to get the user data and add filtering if (from.path.indexOf("modificarCatalogo") == -1 && to.path.indexOf("modificarCatalogo") == -1) { localStorage.removeItem("catalogue"); } next(); }); 方法中使用store变量的更多信息,请参考this question

main.js

router.beforeEach


App.vue

    import router from './router'

    import store from './store' // --> added

    import Vue from 'vue'
    import App from './App.vue'
    import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
    import 'bootstrap/dist/css/bootstrap.css'
    import 'bootstrap-vue/dist/bootstrap-vue.css'
    import axios from 'axios'
    import Vuex from 'vuex'
    // Install BootstrapVue
    import 'leaflet/dist/leaflet.css';

    Vue.use(BootstrapVue)
    // Optionally install the BootstrapVue icon components plugin
    Vue.use(IconsPlugin)
    Vue.use(axios)
    Vue.use(Vuex)
    Vue.config.productionTip = false


    Vue.use(router)

    new Vue({
      router,
      store    // --> added
      render: h => h(App),
    }).$mount('#app')

@ellisdod-谢谢。


Header.vue

mounted () {
    this.$store.dispatch('loadUserFromLocal')
  }