Accessing app inside beforeRouteEnter

筅森魡賤 提交于 2019-12-11 03:05:01

问题


I'd like to show some loading animation in the app root while a component prepares to be rendered by vue router.

Already found this question, proposing the use of navigation guards, and another question, where the accepted answer shows how to use the beforeEach guard to set a variable in app, showing a loading animation.

The problem is that this doesn't work when deep-linking to some route (initial url includes a route path, such as 'someurl#/foo'). The beforeEach guard simply doesn't get called then.

So i switched to the loaded component's beforeRouteEnter guard, which would also allow me to show the loading animation for some components only:

app:

var app = new Vue({
  el: '#app',
  data: { loading: false }
  router: router
});

component:

var Foo = { 
  template: '<div>bar</div>',
  beforeRouteEnter: function(to, from, next) {
    app.loading = true; // 'app' unavailable when deep-linking
    // do some loading here before calling next()...
    next();
  }
}

But then i found that when deep-linking to the component, app isn't available in beforeRouteEnter, as it gets called very early in the initialisation process.

I don't want to set loading to true inside the app data declaration, as i might decide at some point to deep-link to another route, whose component doesn't need a loading animation.


回答1:


Found a workaround using Vue.nextTick:

beforeRouteEnter: function(to, from, next) {
    Vue.nextTick(function(){
      // now app is available
      app.loading = true;
      // some loading to happen here...
      seTimeout(function(){            
        app.loading = false;
        next();  
    }, 1000); 
  })
}

Feels a little hacky, so would be thankful for other suggestions.

Find a demo of this solution here: https://s.codepen.io/schellmax/debug/aYvXqx/GnrnbVPBXezr#/foo




回答2:


I believe, your solution is correct. However, I would suggest using next() function instead. As written in vue-router docs. https://router.vuejs.org/en/advanced/navigation-guards.html

The beforeRouteEnter guard does NOT have access to this, because the guard is called before the navigation is confirmed, thus the new entering component has not even been created yet.

However, you can access the instance by passing a callback to next. The callback will be called when the navigation is confirmed, and the component instance will be passed to the callback as the argument:

beforeRouteEnter (to, from, next) {
  next(vm => {
    vm.$root.loading = true;
  })
}



回答3:


What about using beforeRouteLeave to trigger the loading then have the component toggle it off in mounted.

For the initial load of the app you could have

app:

var app = new Vue({
  el: '#app',
  data() => ({ loading: true }),
  mounted() { this.loading: false },
  router: router
});

then for your components

component:

var Foo = { 
  template: '<div>bar</div>',
  mounted() {
    app.loading = false;
  },
  beforeRouteLeave(to, from , next) {
    switch(to){
      case COMPONENT_TO_SHOW_LOADING_ON:
      case OTHER_COMPONENT:
        app.loading = true;
      default:
    }
  }
}


来源:https://stackoverflow.com/questions/49276470/accessing-app-inside-beforerouteenter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!