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

Posted

技术标签:

【中文标题】Vue Router - 路由加载后调用函数【英文标题】:Vue Router - call function after route has loaded 【发布时间】:2019-02-27 07:14:17 【问题描述】:

我正在做一个项目,我需要在路由完成加载后调用一个函数。但是,当使用“监视”功能时,它只会在路线更改时加载,但会在路线完成加载之前加载。因此,当我尝试运行以页面上的 DOM 元素为目标的脚本时,这些元素还不存在。 Vue Router 中是否有任何功能可以让我等到所有内容都呈现后再运行脚本?

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

【问题讨论】:

通过将它添加到模板本身 beforeRouteEnter (to, from, next) next(vm => SOMEFUNCTION() ) 这似乎解决了我的所有需求 Vue.js Router: Run code when component is ready的可能重复 【参考方案1】:

你应该使用Vue.nextTick

在你的情况下,这将转化为:

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/>`
)

这将在每次路由更改时调用 routeLoaded 方法(我推断这是您所需要的,因为您使用的是&lt;router-view&gt; 元素),如果您也想最初调用它,我会推荐@987654322 @(如示例中所示)或观察者上的 immediate flag

【讨论】:

【参考方案2】:

在我看来,对于这种情况,你应该使用加载组件的组件生命周期方法,要么使用mounted方法,要么使用created方法。

或者如果你的脚本不依赖于任何 vue 组件(存储),你可以使用 router.afterEach 钩子

router.afterEach((to, from) =&gt; if (to.name !== 'ROUTENAME') // do something );

【讨论】:

【参考方案3】:

对我来说,解决方案是在每个页面的 mounted() 挂钩中设置一个自定义事件,并使用 mixin 监听该事件,例如在 body 上。如果您想将其与路由器的afterEach 或路由观察程序严格绑定以确保在触发事件之前路由确实已更改,您可以在afterEach 中设置Promise 并在页面的mounted() 通过事件或通过window 分享resolve 功能。

一个例子:

// 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;
      
    

【讨论】:

【参考方案4】:

如果是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()
            
        ,
    

【讨论】:

【参考方案5】:

您可以通过挂钩到 VueJS lifecycle hooks 来完成此操作:

    使用 VueJS 生命周期挂钩: 这是主要的 VueJS 生命周期钩子的摘要。有关完整说明,请参阅文档。

我。 beforeCreate: 这个函数会在组件创建之前调用

二。 created:这个函数会在组件创建后调用,但是注意组件虽然创建了,但是还没有挂载。所以你将无法访问组件的this。但是,这是创建 Network Requests 的好地方,它将更新数据属性。

三。 mounted:一旦组件被渲染并且元素可以在这里被访问,这个函数就会被调用。这就是你要找的。​​p>

四。 beforeDestroy:该函数在组件销毁前调用。这对于停止您创建的任何侦听器(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/>
  `
)
    使用 Vue Router Navigation Guards:Vue Router 还公开了一些可以挂钩的生命周期挂钩。但是,正如您将在下面看到的,它们不符合您的要求:

我。 beforeRouteEnter:在渲染这个组件的路由被确认之前调用。 oes 无权访问this 组件实例,因为调用此守卫时它尚未创建!

二。 beforeRouteUpdate:当渲染这个组件的路由发生变化时调用,但是这个组件在新的路由中被复用。

三。 beforeRouteLeave: 当渲染这个组件的路由即将被导航离开时调用。

参考资料:

VueJS 文档(生命周期):VueJS Instance

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

【讨论】:

对于 vue 路由器来说,一个钩子是不够的,因为在应用程序中导航时,路由会改变,但钩子不会再次触发

以上是关于Vue Router - 路由加载后调用函数的主要内容,如果未能解决你的问题,请参考以下文章

vue-router,路由按需加载,页面加载完成后,this.$route 获取不到

vue-router 中的导航钩子

vue-router的钩子函数

Vue路由器。使用查询参数调用 this.$router.push() 会导致双重路由器更​​新

Vue Router 路由懒加载

vue-router路由守卫