likes
comments
collection
share

解析keepalive和transition如何在Vue3项目里使用

作者站长头像
站长
· 阅读数 44

keepalive是什么

keep-alive是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

keepailve的基本用法

<script setup>
import { shallowRef } from 'vue'
import CompA from './CompA.vue'
import CompB from './CompB.vue'
// 进行浅层代理,避免不必要的花销
const current = shallowRef(CompA)
</script>

<template>
  <div class="demo">
    <!--切换时,current.value值会发生改变  -->
    <label><input type="radio" v-model="current" :value="CompA" /> A</label>
    <label><input type="radio" v-model="current" :value="CompB" /> B</label>
    <KeepAlive>
      <component :is="current"></component>
    </KeepAlive>
  </div>
</template>

  • 在vue-router中的应用
<keep-alive :include="whiteList" :exclude="blackList" :max="amount">
  <router-view></router-view>
</keep-alive>

include定义缓存白名单,keep-alive会缓存命中的组件;exclude定义缓存黑名单,被命中的组件将不会被缓存,优先级高于前者;max定义缓存组件上限,超出上限使用LRU的策略置换缓存数据。

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

// 组件name为c的组件不缓存(可以保留它的状态或避免重新渲染)
<keep-alive exclude="c"> 
  <component />
</keep-alive>

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

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

配合router的高级使用

router-view也是一个组件,如果直接被包在keepalive里面,那么所有路径匹配到的视图组件都会被缓存,如下:

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

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

  • 使用 include/exclude
  • 使用 meta 属性

1.使用 include (exclude例子类似)

//只有路径匹配到的 name 为 a 组件会被缓存
<keep-alive include="a">
    <router-view></router-view>
</keep-alive>

2.使用 meta 属性

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

<router-view v-if="!$route.meta.keepAlive">
    <!-- 这里是不会被缓存的视图组件,比如 Profile! -->
</router-view>

配合vue-routertransition的高级使用

// App.vue
<script setup>
import { reactive } from 'vue';

const state = reactive({
  transitionName: 'slide-left'
})
const router = useRouter()

router.beforeEach((to, from, next) => {
  if (to.meta.index > from.meta.index) {
    // 从主页面 去到子页面
    state.transitionName = 'slide-left'
  } else if (to.meta.index < from.meta.index) {
    // 子页面回到主页面
    state.transitionName = 'slide-right'
  } else {
    // 平级
    state.transitionName = ''
  }
})

</script>
<template>
<!-- 渲染路由视图 -->
  <router-view v-slot="{ Component }">
    <!-- 过渡效果 -->
    <transition :name="state.transitionName">
      <!-- 缓存组件 -->
      <keep-alive> 
        <component :is='Component' :key="$route.name" v-if="$route.meta.keepAlive" />
      </keep-alive>
    </transition>
  </router-view>
  <!-- 渲染路由视图 -->
  <router-view v-slot="{ Component }">
    <!-- 过渡效果 -->
    <transition :name="state.transitionName">
      <!-- 不缓存组件 -->
      <component :is='Component' :key="$route.name" v-if="!$route.meta.keepAlive" />
    </transition>
  </router-view>

</template>

<style lang="stylus">
.slide-left-enter-active, 
.slide-left-leave-active, 
.slide-right-enter-active, 
.slide-right-leave-active
  height 100%
  /* 提前告知浏览器, 即将会有transform 渐变 */
  will-change transform
  transition all 600ms
  position absolute
  backface-visibility hidden 
.slide-right-enter-from 
  opacity 0
  transform translate3d(-100%, 0, 0)
.slide-right-leave-active 
  opacity 0
  transform translate3d(100%, 0, 0) 
.slide-left-enter-from 
  opacity 0
  transform translate3d(100%, 0, 0)
.slide-left-leave-active 
  opacity 0
  transform translate3d(-100%, 0, 0)
</style>
// router.js
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/views/Home/index.vue'

const routes = [
    {
      path: '/',
      redirect: '/home',
    },
    {
      path: '/home',
      name: 'home',
      component: Home,
      meta: {
        keepAlive: true,
        index: 1
      },
    },
    {
      path: '/detail/:id',
      name:'detail',
      meta: {
        index: 3
      },
      component: () => import('@/views/Detial/index.vue')
    },
    {
      path: '/login',
      name:'login',     
      meta: {
        index: 2
      },
      component: () => import('@/views/Login/index.vue')
    },
    {
      path: '/preferential',
      name: 'preferential',
      meta: {
        index: 1
      },
      component: () => import('@/views/Preferential/index.vue')
    },
    {
      path: '/cart',
      name: 'cart',
      meta: {
        index: 1
      },
      component: () => import('@/views/Cart/index.vue')
    },
    {
      path: '/user',
      name: 'user',
      meta: {
        index: 1,
        isPass: true
      },
      component: () => import('@/views/User/index.vue')
    }
]

 const router = createRouter({
    history: createWebHashHistory(),
    routes
})

export default router

实现的效果:

  • 使用vue的transition组件,在定义router时设置meta.index数值来判断切换动画的使用哪种效果
  • 使用vue的keepailve组件,在定义router时设置meta.keepalive数值来判断是否要进行组件的缓存
转载自:https://juejin.cn/post/7258193813675671589
评论
请登录