简体   繁体   English

Vue Router - 路由加载后调用函数

[英]Vue Router - call function after route has loaded

I'm working on a project where I need to call a function AFTER the route has finished loading.我正在开发一个项目,我需要在路由完成加载后调用一个函数。 However, when using the 'watch' functionality, it only loads on route change, but does so before route has finished loading.但是,当使用“监视”功能时,它只会在路线更改时加载,但会在路线完成加载之前加载。 So when I attempt to run a script that targets DOM elements on the page, those elements don't exist yet.因此,当我尝试运行以页面上的 DOM 元素为目标的脚本时,这些元素还不存在。 Is there any functionality in Vue Router that would allow me to wait until everything is rendered before running the script? Vue Router 中是否有任何功能可以让我等到所有内容都呈现后再运行脚本?

const app = new Vue({
    el: '#app',
    router,
    watch: {
        '$route': function (from, to) {
            function SOMEFUNCTION()
         }   
    },
    data: {
        some data
    },
    template: `
      <router-view/>
  `
})

You should use Vue.nextTick你应该使用Vue.nextTick

In your case this would translate to:在您的情况下,这将转化为:

const app = new Vue({
    el: '#app',
    router,
    watch: {
        $route() {
            this.$nextTick(this.routeLoaded);
         }   
    },
    data() {
        return {};
    },
    methods: {
        routeLoaded() {
           //Dom for the current route is loaded
        }
    },
    mounted() {
/* The route will not be ready in the mounted hook if it's component is async
so we use $router.onReady to make sure it is.
it will fire right away if the router was already loaded, so catches all the cases.
Just understand that the watcher will also trigger in the case of an async component on mount
because the $route will change and the function will be called twice in this case,
it can easily be worked around with a local variable if necessary
*/
       this.$router.onReady(() => this.routeLoaded());
    },
    template: `<router-view/>`
})

This will call the routeLoaded method every time the route changes (which I'm deducing is what you need since you are using the <router-view> element), if you also want to call it initially, I would recommend the mounted hook (like in the example) or the immediate flag on the watcher这将在每次路由更改时调用 routeLoaded 方法(我推断这是您需要的,因为您使用的是<router-view>元素),如果您还想最初调用它,我会推荐安装的钩子(就像在示例中一样)或观察者上的立即标志

In my opinion on this situation, you should use component life cycle method of the loaded component, either use mounted method or created method.在这种情况下,我认为你应该使用加载组件的组件生命周期方法,要么使用mounted方法,要么使用created方法。

or if your script doesn't depend on any vue component (store) you can use router.afterEach hook或者如果您的脚本不依赖于任何 vue 组件(存储),您可以使用 router.afterEach 挂钩

router.afterEach((to, from) => { if (to.name !== 'ROUTENAME'){ // do something }});

The solution for me was to set up a custom event in every page's mounted() hook with a mixin and listen for that event on the body for example.对我来说,解决方案是在每个页面的mounted()钩子中使用 mixin 设置一个自定义事件,并在body上监听该事件。 If you wanted to strictly tie it with the router's afterEach or the route watcher to ensure the route has indeed changed before the event was fired, you could probably set up a Promise in the afterEach and resolve it in the page's mounted() by either the event or sharing the resolve function through the window .如果您想将其与路由器的afterEach或路由观察程序严格绑定以确保在事件触发之前路由确实已更改,您可以在afterEach中设置一个Promise并通过页面的mounted()解决它事件或通过window共享resolve功能。

An example:一个例子:

// Component.vue

    watch: {
      '$route': function (from, to) {
        new Promise((resolve) => {
          window.resolveRouteChange = resolve;
        }).then(() => {
          // route changed and page DOM mounted!
        });
      }
    }

// PageComponent.vue

    mounted() {
      if(window.resolveRouteChange) {
        window.resolveRouteChange();
        window.resolveRouteChange = null;
      }
    }

In case of router-view, we can manually detect router-view.$el change after $route is changed在router-view的情况下,我们可以手动检测router-view.$el在$route改变后的变化

watch: {
        '$route'(to, from) {
            // Get $el that is our starting point
            let start_el = this.$refs.routerview.$el
            this.$nextTick(async function() { await this.wait_component_change(start_el)})
        }
    },
    methods: {
        on_router_view_component_changed: function() { }
        wait_component_change: async function(start_el) {
            // Just need to wait when $el is changed in async manner
            for (let i = 0; i < 9; i++) {
                console.log('calc_has_dragscroll ' + i)
                if(start_el) {
                    if (!start_el.isSameNode(this.$refs.routerview.$el)) {
                        // $el changed - out goal completed
                        this.on_router_view_component_changed()
                        return
                    }
                }
                else {
                    // No start_el, just wait any other
                    if(this.$refs.routerview.$el) {
                        // $el changed - out goal completed too
                        this.on_router_view_component_changed()
                        return
                    }
                }
                await this.$nextTick()
            }
        },
    }

You can accomplish this by hooking into VueJS lifecycle hooks :您可以通过挂钩 VueJS lifecycle hooks来完成此操作:

  1. Use VueJS Lifecycle Hooks: Here is a summary of the major VueJS lifecycle hooks.使用 VueJS 生命周期钩子:这里总结了主要的 VueJS 生命周期钩子。 Please consult the documentation for the full description.请查阅文档以获取完整说明。

i.一世。 beforeCreate : This function will be called before the component is created beforeCreate :该函数将在组件创建之前被调用

ii. ii. created : This function will be called after the component is created, but note although the component is created, it hasn't been mounted yet. created : 这个函数会在组件创建后调用,但是注意组件虽然创建了,但是还没有挂载。 So you won't be able to access the this of the component.所以你将无法访问组件的this However, this is a good place to make Network Requests that will update the data properties.但是,这是进行将更新数据属性的Network Requests的好地方。

iii. iii. mounted : This function is called once the component has been rendered and the elements can be accessed here. mounted :一旦组件被渲染并且可以在此处访问元素,就会调用此函数。 This is what you're looking for.这就是你要找的。

iv. iv. beforeDestroy : This function is called before the component is destroyed. beforeDestroy :在组件被销毁之前调用此函数。 This can be useful to stop any listeners (setTimeout, setInterval..), that you created.这对于停止您创建的任何侦听器(setTimeout、setInterval..)很有用。

See the diagram below for the details.

const app = new Vue({
    el: '#app',
    router,
    mounted(){
      this.someFunction()
    },
    data: {
        some data
    },
    template: `
      <router-view/>
  `
})
  1. Use Vue Router Navigation Guards: Vue Router also expose some lifecycle hooks that can you hook into.使用 Vue Router Navigation Guards:Vue Router 还公开了一些可以挂钩的生命周期挂钩。 However, as you will see below they do not fit your requirements:但是,正如您将在下面看到的,它们不符合您的要求:

i.一世。 beforeRouteEnter : called before the route that renders this component is confirmed. beforeRouteEnter :在渲染该组件的路由被确认之前调用。 oes NOT have access to this component instance, because it has not been created yet when this guard is called! oes 无权访问this组件实例,因为调用此守卫时它尚未创建!

ii. ii. beforeRouteUpdate : called when the route that renders this component has changed, but this component is reused in the new route. beforeRouteUpdate :当渲染此组件的路由发生变化时调用,但此组件在新路由中被重用。

iii. iii. beforeRouteLeave : called when the route that renders this component is about to be navigated away from. beforeRouteLeave :当渲染该组件的路由即将被导航离开时调用。

在此处输入图像描述

References:参考:

VueJS Documentation (LifeCycle): VueJS Instance VueJS 文档(生命周期): VueJS 实例

Vue Router Documentation (Navigation Guards): Navigation Guards Vue路由器文档(导航卫士): 导航卫士

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM