vue 生命周期里面的方法只走一次怎么办?

文章探讨了在Vue项目中遇到的问题,即某些生命周期方法只在首次进入页面时执行。提到了mounted钩子只运行一次,而activated每次激活时都会执行。作者建议记录此解决方案,以备后续项目中类似问题的解决。

有时候在项目中会遇到只有第一次进入页面的时候生命周期里的方法会走,再次进来就不走了

不能每次遇到这个问题都用监听路由的处理,找了一下发现

mounted(){
    // 直走一次
},
activated(){
    // 每次都会走
}

所以记录一下方便后面再次出现这个问题,具体的可不可行还要看大家在实际项目中清况

<think>我们正在处理一个关于Vue和Element UI中el-dialog组件的问题。用户发现当el-dialog中嵌套了一个路由页面(即通过路由加载的组件)时,关闭dialog会触发该路由页面的生命周期钩子(如destroyed)。用户想知道为什么会发生这种情况以及如何解决。 分析原因: 在Vue中,组件的生命周期钩子会在组件被销毁时触发。当el-dialog关闭时,如果它内部嵌套的组件被销毁,那么这些组件的生命周期钩子(如beforeDestroy和destroyed)就会被触发。 但是,这里有一个特殊情况:用户嵌套的是一个路由页面。这意味着在dialog内部使用了<router-view>来渲染一个路由对应的组件。当dialog关闭时,这个<router-view>会被移除,从而导致路由组件被销毁,因此触发了它的销毁生命周期钩子。 然而,用户可能期望的是:当dialog关闭时,这个路由组件不被销毁,以便在下次打开dialog时能够保持之前的状态(例如表单输入的内容等)。这就是问题所在。 解决方案: 1. 使用v-if控制路由组件的挂载与销毁:默认情况下,当dialog关闭时,我们可能希望保留路由组件的状态,但又不希望它被销毁。我们可以通过将路由组件包裹在一个<keep-alive>组件中来实现缓存。但是,请注意,<keep-alive>只能缓存组件实例,而不会缓存路由。因此,我们需要在路由配置中设置组件的缓存,或者使用<keep-alive>包裹<router-view>。 2. 另一种方法是,在dialog关闭时,我们并不销毁整个路由视图,而是通过v-show来控制dialog的显示隐藏,这样内部的组件就不会被销毁。但是,el-dialog组件默认情况下在关闭时并不会销毁其内容(除非设置destroy-on-close属性),所以我们需要检查是否设置了销毁属性。 3. 然而,根据Element UI的文档,el-dialog有一个属性`destroy-on-close`,默认为false,即关闭时不会销毁子组件。所以,如果用户没有设置这个属性为true,那么关闭dialog时子组件并不会被销毁。那么为什么路由组件会被销毁呢?可能是因为路由发生了变化,或者因为dialog关闭时导致<router-view>被移除,从而销毁了路由组件。 因此,我们需要确保在dialog关闭时,路由组件不会被销毁。有几种方法方法一:使用v-if控制路由组件的加载,但这样每次打开dialog都会重新加载组件(即重新创建),如果用户希望保持状态,则不可取。 方法二:使用<keep-alive>来缓存路由组件。这样即使dialog关闭,路由组件也不会被销毁,而是被缓存起来,下次打开时状态得以保留。 具体步骤: 在App.vue(或包含<router-view>的父组件)中,用<keep-alive>包裹<router-view>,但这样会缓存所有路由。我们可能只希望缓存dialog中的那个路由。 方法三:在dialog内部使用<keep-alive>包裹<router-view>。但是,由于<router-view>是动态组件,我们可以这样写: ```html <el-dialog :visible.sync="dialogVisible"> <keep-alive> <router-view v-if="dialogVisible"></router-view> </keep-alive> </el-dialog> ``` 但是,注意:当dialogVisible为false时,<router-view>会被销毁,即使包裹了<keep-alive>,因为v-if是条件渲染,当条件为false时组件会被销毁。而<keep-alive>只能缓存它包裹的组件,当组件被销毁时,缓存也就没有了。 因此,我们需要让<router-view>在dialog关闭时不被销毁,我们可以使用v-show来控制,但是<router-view>不支持v-show(因为v-show只是切换display样式,而路由组件在隐藏时可能仍然需要保持活动状态)。所以,我们可以将<router-view>包裹在一个div中,然后对这个div使用v-show,但是这样并不能阻止路由组件的销毁,因为路由组件的销毁是由路由变化或者父组件的卸载引起的。 方法四:我们可以在dialog关闭时,不卸载路由组件,而是将其隐藏。但是,el-dialog在关闭时默认会移除其内部的内容(通过v-if),所以我们需要改变el-dialog的行为,使其在关闭时只是隐藏而不销毁内容。我们可以通过设置`destroy-on-close`为false(默认就是false)来避免销毁。同时,我们需要确保路由不会因为dialog的关闭而改变。也就是说,即使dialog关闭了,当前的路由仍然保持。这样,路由组件就不会被销毁。 但是,用户可能希望关闭dialog时路由也改变?这需要根据业务需求来定。 因此,我们有两种思路: 思路1:在关闭dialog时,不改变当前路由。这样,路由组件就不会被销毁。但是,这样会导致即使dialog关闭了,路由仍然保持,可能会影响其他功能(比如浏览器回退操作)。 思路2:在关闭dialog时,改变路由,但我们使用<keep-alive>缓存该路由组件,这样即使路由组件被销毁,再次打开时(路由再次激活)可以从缓存中恢复。 具体实现: 1. 在路由配置中,为需要缓存的路由组件设置meta属性,比如keepAlive: true。 2. 在包含<router-view>的地方,根据路由的meta属性决定是否使用<keep-alive>: ```html <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view> ``` 3. 在dialog关闭时,我们可能需要改变路由,比如跳转到一个空路由或者回到之前的页面?但是用户可能希望下次打开dialog时还能看到之前的状态。所以,我们需要在关闭dialog时不要改变路由?或者改变路由但是保留组件的缓存。 然而,在dialog中嵌套路由页面,这种做法本身可能不太符合常规。因为路由通常用于整个页面的切换,而dialog是页面内的一个弹出层。所以,另一种做法是:不要使用路由来加载dialog的内容,而是使用组件的方式直接引入,然后通过v-if来控制组件的显示(这样我们可以通过<keep-alive>包裹这个组件来缓存)。这样,关闭dialog时,我们只是隐藏这个组件,并不会销毁它(如果使用<keep-alive>)。 所以,如果可能,建议避免在dialog内使用<router-view>,而是将需要展示的组件直接引入,并用<keep-alive>包裹。 但是,如果用户确实需要在dialog内使用路由,那么我们可以采用以下方式: 在父组件中: ```html <el-dialog :visible.sync="dialogVisible" :destroy-on-close="false"> <keep-alive> <router-view v-if="dialogVisible"></router-view> </keep-alive> </el-dialog> ``` 注意:这里设置`destroy-on-close`为false(其实默认就是false),这样dialog关闭时不会销毁内部组件。同时,我们使用v-if来控制<router-view>的显示,当dialogVisible为true时才渲染<router-view>,这样当dialog关闭时,<router-view>会被销毁,但是因为包裹在<keep-alive>中,所以组件实例会被缓存。下次打开dialog时,会从缓存中恢复。 但是,这里有一个问题:当dialog关闭时,<router-view>被销毁(因为v-if为false),那么路由组件确实会被销毁,但是<keep-alive>会保存它的实例。当下次再次渲染时,会从缓存中取出实例,不会重新创建(所以不会触发created、mounted等生命周期,但是会触发activated钩子)。 然而,我们还需要考虑路由的变化。当dialog关闭时,我们可能希望路由回到之前的状态?或者保持不变?这需要根据业务逻辑来调整。 另外,注意:当<router-view>被销毁时,它内部的路由组件也会被销毁,但是因为有<keep-alive>,所以路由组件的实例会被缓存,所以不会触发destroyed钩子,而是触发deactivated钩子。当再次打开dialog时,会触发activated钩子。 但是,用户观察到的生命周期钩子触发,可能是destroyed钩子被触发,说明组件被销毁了。所以,如果我们使用<keep-alive>,那么destroyed钩子就不会在关闭dialog时触发,而是在缓存被清除时才会触发。 因此,解决方案总结: 1. 使用<keep-alive>包裹<router-view>,并确保在dialog关闭时,路由组件不会被销毁(通过设置destroy-on-close为false,并且使用v-if来控制<router-view>的渲染,这样关闭dialog时<router-view>被销毁,但路由组件实例被缓存)。 2. 这样,关闭dialog时,路由组件会触发deactivated钩子,而不会触发destroyed钩子。打开dialog时,会触发activated钩子。 但是,如果用户希望关闭dialog时路由也改变(比如返回上一级),那么我们需要在关闭dialog时手动改变路由。这样,路由改变会导致原来的路由组件被销毁(即使有<keep-alive>,如果路由变化,那么该路由组件也会被移除缓存?)。所以,我们需要在关闭dialog时保持当前路由不变?这可能会造成URL和实际显示不一致。 因此,在dialog中使用路由可能并不是最佳实践。我们可能需要重新考虑设计:使用普通组件而不是路由组件。 如果用户坚持使用路由,那么需要权衡:在关闭dialog时是否改变路由。如果不改变路由,那么URL会保持,用户可能觉得奇怪。如果改变路由,那么路由组件会被销毁(即使缓存了,但路由变化后,该组件实例会被从缓存中移除?)。 实际上,<keep-alive>缓存的是组件实例,它根据组件的name或者路由的匹配规则来缓存。当路由变化时,如果新路由匹配到同一个组件,并且我们使用了<keep-alive>的include属性来指定缓存,那么原来的组件实例会被缓存。但是,如果路由变化到了不同的组件,那么原来的组件实例会被销毁。 所以,如果我们在关闭dialog时改变路由(比如跳转到另一个路由),那么当前路由组件会被销毁(缓存也会被清除)。如果我们在关闭dialog时不改变路由,那么路由组件会一直存在,直到路由改变。 因此,我们可以在关闭dialog时保留当前路由,然后当用户再次打开dialog时,由于路由没有变化,所以组件可以直接从缓存中激活(不会触发created和mounted)。这样,关闭dialog时,组件只是被停用(deactivated),不会被销毁。 具体操作: 1. 打开dialog时,通过路由跳转到dialog对应的路由(比如/dialog-page)。 2. 关闭dialog时,我们并不跳转路由,而是将dialog隐藏。这样,路由仍然是/dialog-page,但是dialog不可见。这显然不是我们想要的,因为URL会一直显示/dialog-page。 所以,我们需要在关闭dialog时,将路由跳转回之前的路由。但是这样,路由变化会导致/dialog-page对应的组件被销毁(即使有缓存,因为路由已经离开了,所以组件实例会被销毁?)。实际上,<keep-alive>可以缓存多个路由,只要路由组件的name在include列表中,那么该组件实例就会被缓存。当路由再次回到/dialog-page时,会从缓存中激活。 因此,我们可以这样做: 1. 在打开dialog时,使用$router.push()跳转到dialog对应的路由(比如/dialog-page)。 2. 在关闭dialog时,使用$router.go(-1)返回上一级路由(或者使用$router.push()跳转回之前的路由)。 这样,路由变化会触发/dialog-page路由组件的停用(deactivated),并被缓存。当再次打开dialog(再次跳转到/dialog-page)时,组件激活(activated),不会重新创建。 但是,用户可能会通过浏览器的后退按钮关闭dialog,所以我们需要监听路由变化,当路由变为非
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值