28、Vue keep-alive实践总结(二)

keep-alive简介

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
用法也很简单:

<keep-alive>
  <component>
    <!-- 该组件将被缓存! -->
  </component>
</keep-alive>

props

  • include - 字符串或正则表达,只有匹配的组件会被缓存
  • exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
// 组件 a
export default {
  name: 'a',
  data () {
    return {}
  }
}
<keep-alive include="a">
  <component>
    <!-- name 为 a 的组件将被缓存! -->
  </component>
</keep-alive>可以保留它的状态或避免重新渲染
<keep-alive exclude="a">
  <component>
    <!-- 除了 name 为 a 的组件都将被缓存! -->
  </component>
</keep-alive>可以保留它的状态或避免重新渲染
<keep-alive include="a,b">
  <!-- 将缓存name为a或者b的组件,结合动态组件使用 -->
  <component :is="view"></component>
</keep-alive>

<!-- 使用正则表达式,需使用v-bind -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<!-- 动态判断 -->
<keep-alive :include="includedComponents">
  <router-view></router-view>
</keep-alive>

遇见 vue-router

西湖雨好大,借把伞躲躲雨...
router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存:

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

然而产品汪总是要改需求,拦都拦不住...

问题

如果只想 router-view 里面某个组件被缓存,怎么办?

  • 使用 include/exclude
  • 增加 router.meta 属性

使用 include/exclude

// 组件 a
export default {
  name: 'a',
  data () {
    return {}
  }
}
<keep-alive include="a">
    <router-view>
        <!-- 只有路径匹配到的视图 a 组件会被缓存! -->
    </router-view>
</keep-alive>

exclude 例子类似。

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

增加 router.meta 属性

// routes 配置
export default [
  {
    path: '/',
    name: 'home',
    component: Home,
    meta: {
      keepAlive: true // 需要被缓存
    }
  }, {
    path: '/:id',
    name: 'edit',
    component: Edit,
    meta: {
      keepAlive: false // 不需要被缓存
    }
  }
]
<keep-alive>
    <router-view v-if="$route.meta.keepAlive">
        <!-- 这里是会被缓存的视图组件,比如 Home! -->
    </router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive">
    <!-- 这里是不被缓存的视图组件,比如 Edit! -->
</router-view>

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

demo方式一:

//App.vue
<template>
    <router-view></router-view>
</template>
<!-- Page1页面 -->
<template>
  <div class="hello">
    <h1>Vue</h1>
    <h2>{{msg}}</h2>
    <input v-model="msg" placeholder="输入框" />
  </div>
</template>
<script>
export default {
    name:'page1',
    data(){
        return {
            msg:''
        }
    }
}
</script>
<!-- Hello页面 -->
<template>
  <div class="hello">
    <h1>hello</h1>
  </div>
</template>
<script>
export default {
   name:'hello'
}
</script>

正常情况下效果:
操作方式:
(1) 在Page1页面输入框输入“234234”,然后手动跳转到Hello页面;
(2) 回到Page1页面发现之前输入的"234234"依然保留,说明页面信息成功保存在内存中;


图1 进入Page1页面,并输入"234234"

图2 跳转到Hello页面

图3 返回Page1页面,输入框数据会被保留

keep-alive结合exclude不缓存name为XXXX的组件这里的name不是router中的name,而是组件中的name

//App.vue
<template>
<div>
  <keep-alive exclude="hello">//这里exclude="hello"中的`hello`是Hello页面中`export default {name:'hello'}`的hello
    <router-view></router-view>
</keep-alive>
</div>
</template>

使用效果

demo方式二:

结合router,缓存部分页面
使用$route.meta的keepAlive属性:

//App.vue

<template>
<div>
  <keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>

需要在router中设置router的元信息meta:

//...router.js
import Vue from 'vue';
import Router from 'vue-router';
const Hello = () => import('@/components/Hello')//这种方式懒加载也可以正常方式引入
const Page1 = () => import('@/components/Page1')//
Vue.use(Router);
export default new Router({
    routes: [
      {
        path: '/',
        component: Hello,
        meta: {
            keepAlive: false // 需要被缓存
          }
      },
      {
        path: '/page1',
        component: Page1,
        meta: {
            keepAlive: true // 需要被缓存
          }
      }
    ]
  })

以上面router的代码为例:

<!-- Page1页面 -->
<template>
  <div class="hello">
    <h1>Vue</h1>
    <h2>{{msg}}</h2>
    <input v-model="msg" placeholder="输入框" />
  </div>
</template>
<script>
export default {
    name:'page1',
    data(){
        return {
            msg:''
        }
    }
}
</script>
<!-- Hello页面 -->
<template>
  <div class="hello">
    <h1>hello</h1>
  </div>
</template>

操作同上---效果同上:
当然,也可以通过动态设置route.meta的keepAlive属性来实现其他需求,
例子:

  • 首页是A页面
  • B页面跳转到A,A页面需要缓存
  • C页面跳转到A,A页面不需要被缓存
    思路是在每个路由的beforeRouteLeave(to, from, next)钩子中设置to.meta.keepAlive
    在 A 路由里面设置 meta 属性:
{
        path: '/',
        name: 'A',
        component: A,
        meta: {
            keepAlive: true // 需要被缓存
        }
}

在 B 组件里面设置 beforeRouteLeave:

export default {
        data() {
            return {};
        },
        methods: {},
        beforeRouteLeave(to, from, next) {
             // 设置下一个路由的 meta
            to.meta.keepAlive = true;  // 让 A 缓存,即不刷新
            next();
        }
};

在 C 组件里面设置 beforeRouteLeave:

export default {
        data() {
            return {};
        },
        methods: {},
        beforeRouteLeave(to, from, next) {
            // 设置下一个路由的 meta
            to.meta.keepAlive = false; // 让 A 不缓存,即刷新
            next();
        }
};

这样便能实现 B 回到 A,A 不刷新;而 C 回到 A 则刷新。
亲测有效哦~

keep-alive生命周期钩子函数:activated、deactivated

使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。