jjzjj

Vue缓存路由(keep-alive)以及新的生命周期

code_dream_wq 2023-04-14 原文

一.概念

也就是说,kee-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存 keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性。

三.Props

include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例
两个新的生命周期钩子
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。只适用于keep-alive

四. 生命周期

当组件在 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。

activated
路由组件被激活时触发。(当进入缓存的路由组件时触发)
使用 keep-alive 会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在 activated 阶段获取数据,承担原来 created 钩子函数中获取数据的任务
你应该初始读取一次数据,比如在created里面, 而activated第一次创建页面时不会激活,缓存之后,第二次进入才会开始激活
// 当缓存组件被激活的时候执行

 activated(){
        this.userName = this.$route.query.id
    },

deactivated
路由组件失活时触发。(当离开缓存的路由组件时触发)

五.用法(两种方式)

1.根据条件缓存页面

// 所有路径匹配到的视图组件都会被缓存! 
<keep-alive>
    <router-view></router-view>
</keep-alive>

// 只缓存组件name为aa或者bb的组件
<keep-alive include="aa,bb"> 
  <component />
</keep-alive>

// 组件name为cc的组件不缓存
<keep-alive exclude="cc"> 
  <component />
</keep-alive>

// 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存aa组件
<keep-alive include="aa,bb" exclude="bb"> 
  <component />
</keep-alive>

// 如果缓存的组件超过了max设定的值3,那么将删除第一个缓存的组件
<keep-alive exclude="c" max="3"> 
  <component />
</keep-alive>

缺点:需要知道组件的 name,项目复杂的时候不是很好的选择

3.结合路由缓存部分页面

优点:不需要例举出需要被缓存组件名称

//在 router 目录下的 index.js 文件里
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import Layout from '@/layout'
export default new Router = [
  {
    path: '/admin',
    component: Layout,
    redirect: '/admin/user',
    alwaysShow: true, 
    name: 'Admin',
    meta: {
      title: '系统管理',
      icon: 'documentation'
    },
    children: [
      {
        path: 'user',
        component: () => import('@/views/admin/user'),
        name: 'User',
        meta: {
          title: '用户管理',
          keepAlive: true // 需要缓存
        }
      },
      {
        path: 'user2',
        component: () => import('@/views/admin/user2'),
        name: 'User2',
        meta: {
          title: '用户管理2',
          keepAlive: false // 不需要缓存,默认不缓存,可以不写
        }
      }
    ]
  }
]

App.vue

<template>
  <div id="app">
    <!-- <router-view/> -->
     <!-- 可以被缓存的视图组件 -->
     <keep-alive>
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <!-- 不可以被缓存的视图组件 -->
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

<style>
</style>

使用 router.meta 拓展

当然,也可以通过动态设置route.meta的keepAlive属性来实现其他需求,
首页是A页面
B页面跳转到A,A页面需要缓存
C页面跳转到A,A页面不需要被缓存
思路是在每个路由的beforeRouteLeave(to, from, next)钩子中设置to.meta.keepAlive:

A的路由

{
    path: '/',
    name: 'A',
    component: A,
    meta: {
        keepAlive: true // 需要被缓存
    }
}
export default {
    data() {
        return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
         // 设置下一个路由的 meta
        to.meta.keepAlive = true;  // B 跳转到 A 时,让 A 缓存,即不刷新
        next();
    }
};
export default {
    data() {
        return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
        // 设置下一个路由的 meta
        to.meta.keepAlive = false; // C 跳转到 A 时让 A 不缓存,即刷新
        next();
    }
};

六/实现前进刷新,返回不刷新

所说的前进刷新后退不刷新是指组件是否重新渲染,比如列表list页面,点击其中的每一项进入详情detail页面,然后从detail页面后退到列表list页面时,list页面没有重新渲染,也没有重新发送ajax请求

routes: [{
        path: '/',
        name: 'home',
        component: Home,
        meta: {
            keepAlive: false //此组件不需要被缓存
        }
    },
    {
        path: '/list',
        name: 'list',
        component: List,
        meta: {
            keepAlive: true //此组件需要被缓存
        }
    },
    {
        path: '/detail',
        name: 'detail',
        component: Detail,
        meta: {
            keepAlive: false // 此组件需要被缓存
        }
    }
]

第一次进入keep-alive组件时,其生命周期执行顺序

beforeRouteEnter --> created --> mounted --> activated --> deactivated

非首次进入时,其生命周期执行顺序:

beforeRouteEnter -->activated --> deactivated

,非首次进入keep-alive组件时,正常的vue组件生命周期函数是不会在执行,而会执行keep-alive新增的两个周期钩子函数。同时也可以看出离开keep-alive组件时其destroy周期函数并没有执行,从侧面证明缓存组件并没有销毁。根据介绍,我们可以:

通过利用keep-alive提供activated钩子函数来决定是否进行ajax请求来更新组件,以及deactivated钩子函数来重置页面相关状态。

首先,在每个路由元信息meta中添加一个isBack字段

    ...
    {
        path: '/list',
        name: 'list',
        component: List,
        meta: {
            keepAlive: true, //此组件需要被缓存
            isBack: false
        }
    }
    ...

(list.vue页面 )然后,借助beforeRouteEnter钩子函数来判断页面来源

    beforeRouteEnter(to, from, next) {
      if(from.name === 'detail') { //判断是从哪个路由过来的,若是detail页面不需要刷新获取新数据,直接用之前缓存的数据即可
          to.meta.isBack = true;
      }
      next();
    },

最后,需要借助keep-alive提供钩子函数activated来完成是否更新:

  activated() {
    if(!this.$route.meta.isBack) {
      // 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据
      this.getData(); // ajax获取数据方法
    }
    // 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据
    this.$route.meta.isBack = false
  },

特殊情况,在keep-alive组件前进的页面刷新导致keep-alive组件状态丢失
继续以上面的list、detail页面为例,在进入详情页面后,然后刷新,这时列表页面的缓存的数据都丢失了,由于上面的判断规则也会导致不会重新获取数据。所以对于这种问题,还需要额外加一些判断条件。由于keep-alive第一次进入时会执行created方法,所以利用这点加一个标识来加以判断:

   //第一次进入keep-alive路由组件时
    created() {
      this.isFirstEnter = true;
     // 只有第一次进入或者刷新页面后才会执行此钩子函数,使用keep-alive后(2+次)进入不会再执行此钩子函数
   },

  activated() {
     if(!this.$route.meta.isBack || this.isFirstEnter){
         // 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据
         // 如果isFirstEnter是true,表明是第一次进入此页面或用户刷新了页面,需获取新数据
         this.data = ''// 把数据清空,可以稍微避免让用户看到之前缓存的数据
         this.getData();
     }
     // 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据
     this.$route.meta.isBack=false
     // 恢复成默认的false,避免isBack一直是true,导致每次都获取新数据
     this.isFirstEnter=false;
   },

列表页回到上次浏览位置

条件:1、列表页不可使用懒加载延迟加载数据,2、列表页需要使用keepAlive缓存

beforeRouteLeave(to,from,next){  //离开页面之前将高度存储到sessionStorage。这里不建议用localStorage,因为session在关闭浏览器时会自动清除,而local则需要手动清除,有点麻烦。
sessionStorage.setItem('scrollH',document.getElementById('demo').scrollTop)
    next()
},
activated(){   //在activated生命周期内,从sessionStorage中读取高度值并设置到dom
    if(sessionStorage.getItem('scrollH')){
        document.getElementById('demo').scrollTop=sessionStorage.getItem('scrollH')
    }
},

可使用ref

this.$refs.demo.scrollTop =50;

其他:

参考:
1路由缓存
2前进后退刷新问题,
3.一直缓存,判断是否第一次进入,或者是否返回,返回重新请求数据刷新页面,不是的话默认缓存

有关Vue缓存路由(keep-alive)以及新的生命周期的更多相关文章

  1. ruby-on-rails - rails : keeping DRY with ActiveRecord models that share similar complex attributes - 2

    这似乎应该有一个直截了当的答案,但在Google上花了很多时间,所以我找不到它。这可能是缺少正确关键字的情况。在我的RoR应用程序中,我有几个模型共享一种特定类型的字符串属性,该属性具有特殊验证和其他功能。我能想到的最接近的类似示例是表示URL的字符串。这会导致模型中出现大量重复(甚至单元测试中会出现更多重复),但我不确定如何让它更DRY。我能想到几个可能的方向...按照“validates_url_format_of”插件,但这只会让验证干给这个特殊的字符串它自己的模型,但这看起来很像重溶液为这个特殊的字符串创建一个ruby​​类,但是我如何得到ActiveRecord关联这个类模型

  2. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby - 如何在 Ubuntu 中清除 Ruby Phusion Passenger 的缓存? - 2

    我试过重新启动apache,缓存的页面仍然出现,所以一定有一个文件夹在某个地方。我没有“公共(public)/缓存”,那么我还应该查看哪些其他地方?是否有一个URL标志也可以触发此效果? 最佳答案 您需要触摸一个文件才能清除phusion,例如:touch/webapps/mycook/tmp/restart.txt参见docs 关于ruby-如何在Ubuntu中清除RubyPhusionPassenger的缓存?,我们在StackOverflow上找到一个类似的问题:

  6. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  7. ruby-on-rails - Ruby on Rails 计数器缓存错误 - 2

    尝试在我的RoR应用程序中实现计数器缓存列时出现错误Unknownkey(s):counter_cache。我在这个问题中实现了模型关联:Modelassociationquestion这是我的迁移:classAddVideoVotesCountToVideos0Video.reset_column_informationVideo.find(:all).eachdo|p|p.update_attributes:videos_votes_count,p.video_votes.lengthendenddefself.downremove_column:videos,:video_vot

  8. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

    我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

  9. ruby-on-rails - 如何在发布新的 Ruby 或 Rails 版本时收到通知? - 2

    有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:

  10. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

随机推荐