Home  >  Q&A  >  body text

javascript - vue+vue-router+vuex+axios+elementUI uses the background management interface to report an error when clicking the menu after refreshing it

The requirement is to build a background management interface with related functions of permission management. The relevant ideas are based on the article addRoutes to implement background management functions. The specific method is to return the permissions owned by the role in the background when logging in, by calling The addRoutes method loads dynamically. Vuex manages the routing loading status and loaded routes, and stores them in sessionStorage during the commit operation. Under normal circumstances, after logging in, the menu displays normally and the relevant interface can be clicked. After the F5 page is refreshed, it is taken out from sessionStorage and re- Load routing data. At this time, the menu can still be displayed normally, but an error is thrown when clicking:

vue.esm.js?65d7:431 [Vue warn]: Error in beforeCreate hook: "TypeError: Cannot read property 'call' of null"

Beginner, please help me find out where the problem lies

login.vue code snippet

computed:{
      ...mapGetters([
          'menuitems',
          'isLoadRoutes'
          // ...
      ])
    },
    methods: {
      rememberPwd(){
        if(this.checked){
            localStorage.setItem('account',this.ruleForm2.account);
            localStorage.setItem('password',this.ruleForm2.checkPass );
        }
      },
      removePwd(){
        if(this.checked){
            localStorage.removeItem('account');
            localStorage.removeItem('password');
        }
      },
      handleReset2() {
        this.$refs.ruleForm2.resetFields();
        this.removePwd();
      },
      handleSubmit2(ev) {
        var _this = this;
        this.$refs.ruleForm2.validate((valid) => {
          if (valid) {
            //_this.$router.replace('/table');
            this.logining = true;
            //NProgress.start();
            var loginParams = { username: this.ruleForm2.account, password: this.ruleForm2.checkPass };
            requestLogin(loginParams).then(res => {
              this.logining = false;
              //NProgress.done();
              if (res.data.resultCode !== "SUCCESS") {
                this.$message({
                  message: res.data.resultDesc,
                  type: 'error'
                });
              } else {
                this.loginUser=res.data.userProfile;
                this.routes=res.data.routes;
                if(this.loginUser.doRemove){
                  this.removePwd();
                }else{
                  this.rememberPwd();
                }
                sessionStorage.setItem('user', JSON.stringify(res.data.userProfile));
                sessionStorage.setItem('security', JSON.stringify(this.routes));
                this.addMenu(this.routes);
                /*this.$router.push(this.routes);*/
                if (!this.isLoadRoutes) {
                  this.$router.addRoutes(this.routes);
                  for(let route of this.routes){
                      console.info(JSON.stringify(route));
                     this.$router.options.routes.push(route);
                  }
                  this.loadRoutes();
                }
                console.info('push to home')
                this.$router.push({ path: '/' });
              }
            });
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      ...mapActions([
         'addMenu',
         'loadRoutes'
      ])
    }
  

store.js related code

import {ADD_MENU,LOAD_ROUTES,INIT_FROM_LS} from './mutations_type'

export const state = {
    items: [
    ],
    isLoadRoutes: false
}

export const mutations = {
    [ADD_MENU] (state, menuItems) {
        console.info('addmenu mutations');
        if (menuItems.length === 0) {
            state.items = []
        } else {
            state.items = menuItems;
            sessionStorage.setItem('state.items',JSON.stringify(state.items));
        }
    },
    [LOAD_ROUTES] (state) {
        state.isLoadRoutes = !state.isLoadRoutes;
        sessionStorage.setItem('state.isLoadRoutes',JSON.stringify(state.isLoadRoutes));
        console.info('change load routes states ' +state.isLoadRoutes);
    },
    [INIT_FROM_LS](state){
        if (sessionStorage.getItem('state.items')) {
            state.items = JSON.parse(localStorage.getItem('state.items'));
        }
        if (sessionStorage.getItem('state.isLoadRoutes')) {
            state.isLoadRoutes = JSON.parse(localStorage.getItem('state.isLoadRoutes'));
        }
        console.info('init from ls '+JSON.stringify(state));
    }

}

getters.js

const menuitems = state => state.items
const isLoadRoutes = state => state.isLoadRoutes
export {
    menuitems,
    isLoadRoutes
}

action.js

import {ADD_MENU,LOAD_ROUTES,INIT_FROM_LS} from './mutations_type'

export const addMenu = ({ commit }, menuItems) => {
    if (menuItems.length > 0) {
        commit(ADD_MENU, menuItems)
    }
}

export const loadRoutes = ({commit}) => {
    commit(LOAD_ROUTES)
}

export const initFromLs=({commit})=>{
    commit(INIT_FROM_LS)
}

store.js

import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as getters from './getters'
import {mutations,state} from './menu'
Vue.use(Vuex)


// 创建 store 实例
export default new Vuex.Store({
    state,
    actions,
    getters,
    mutations
})

main.js

import Vue from 'vue'
import App from './App'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-default/index.css'
import VueRouter from 'vue-router'
import store from './vuex/store'
import Vuex from 'vuex'
import 'font-awesome/css/font-awesome.min.css'

import {state} from  './vuex/menu'
import Login from './views/Login.vue'
import NotFound from './views/404.vue'
import Home from './views/Home.vue'

Vue.use(ElementUI)
Vue.use(VueRouter)
Vue.use(Vuex)

const router = new VueRouter({
    routes:[
            {
                path: '/login',
                component: Login,
                name: '',
                hidden: true
            },
            {
                path: '/404',
                component: NotFound,
                name: '',
                hidden: true
            },
            {
                path: '/',
                component: Home,
                hidden: true
            },
            ...generateRoutesFromMenu()
        ]
})

// Menu should have 2 levels.
function generateRoutesFromMenu (routes = []) {
    store.dispatch('initFromLs');
    for (let i = 0, l = state.items.length; i < l; i++) {
        let item = state.items[i]
        if (item.path) {
            routes.push(item);
        }
    }
    console.info('generate menu = '+state.items +' routes = '+routes);
    return routes
}

router.beforeEach((to, from, next) => {
  //NProgress.start();
  if (to.path == '/login') {
    sessionStorage.removeItem('user');
    sessionStorage.removeItem('security');
    sessionStorage.removeItem('state.items');
    sessionStorage.removeItem('state.isLoadRoutes');
  }
  let user = JSON.parse(sessionStorage.getItem('user'));
  if (!user && to.path != '/login') {
    next({ path: '/login' })
  } else {
    next();
  }
})


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

After logging in for the first time, click on the left menu as normal

After F5 refreshes, clicking the menu throws an error

.]

error code

vue.esm.js?65d7:520 TypeError: Cannot read property 'call' of null
    at callHook (eval at <anonymous> (app.js:770), <anonymous>:2533:20)
    at VueComponent.Vue._init (eval at <anonymous> (app.js:770), <anonymous>:3969:5)
    at new VueComponent (eval at <anonymous> (app.js:770), <anonymous>:4140:12)
    at createComponentInstanceForVnode (eval at <anonymous> (app.js:770), <anonymous>:3495:10)
    at init (eval at <anonymous> (app.js:770), <anonymous>:3329:45)
    at createComponent (eval at <anonymous> (app.js:770), <anonymous>:4871:9)
    at createElm (eval at <anonymous> (app.js:770), <anonymous>:4814:9)
    at VueComponent.patch [as __patch__] (eval at <anonymous> (app.js:770), <anonymous>:5309:9)
    at VueComponent.Vue._update (eval at <anonymous> (app.js:770), <anonymous>:2300:19)
    at VueComponent.updateComponent (eval at <anonymous> (app.js:770), <anonymous>:2416:10)
handleError @ vue.esm.js?65d7:520
callHook @ vue.esm.js?65d7:2534
Vue._init @ vue.esm.js?65d7:3968
VueComponent @ vue.esm.js?65d7:4139
createComponentInstanceForVnode @ vue.esm.js?65d7:3494
init @ vue.esm.js?65d7:3328
createComponent @ vue.esm.js?65d7:4870
createElm @ vue.esm.js?65d7:4813
patch @ vue.esm.js?65d7:5308
Vue._update @ vue.esm.js?65d7:2299
updateComponent @ vue.esm.js?65d7:2415
get @ vue.esm.js?65d7:2754
run @ vue.esm.js?65d7:2824
flushSchedulerQueue @ vue.esm.js?65d7:2591
(anonymous) @ vue.esm.js?65d7:652
nextTickHandler @ vue.esm.js?65d7:599
vue.esm.js?65d7:431 [Vue warn]: Failed to mount component: template or render function not defined.

found in

---> <Home> at C:\Users\Dio\git\vue-admin\src\views\Home.vue
       <App> at C:\Users\Dio\git\vue-admin\src\App.vue
         <Root>
天蓬老师天蓬老师2658 days ago2492

reply all(3)I'll reply

  • 为情所困

    为情所困2017-06-12 09:32:35

    After testing, I found that the root cause of this problem is that the routing component parameter cannot be parsed after being converted into a string by json and then converted back into an object. I tried directly using import Home from 'xxx' to replace the component. After the value, routing information will be displayed normally. But it still hasn’t solved the problem fundamentally, it’s a headache

    reply
    0
  • 三叔

    三叔2017-06-12 09:32:35

    After roughly looking at it, I think you don’t need to save all the routing information in sessionStorage. You just need to save the information obtained by logging in

    reply
    0
  • 某草草

    某草草2017-06-12 09:32:35

    I think you can refer to this article/a/11...

    reply
    0
  • Cancelreply