vue中動態化的按需使用keep-alive

farsun發表於2021-09-09

主要講下啥是 keep-alive、具體到專案中怎麼用的問題。
專案相關:

1、啥是 keep-alive?

  • 就是快取,我們還是來看看具體的使用場景。

  • 首先簡單一點,第一種比較普遍的場景,當我們從首頁–>列表頁–>商詳頁–>再返回,這時候列表頁應該是需要keep-alive的。

  • 然後第二種,當我們從首頁–>列表頁–>商詳頁–>返回到列表頁(需要快取)–>返回到首頁(需要快取)–>再次進入列表頁(不需要快取),這時候就是按需來控制頁面的keep-alive了。
    圖片描述

  • 下面我們來說說在vue中如何具體實現,我會說兩種方式。

2、meta 路由元資訊

(1)介紹

  • 第一種就是使用 vue-router 提供的 meta 物件,給需要快取如首頁、列表頁、商詳等新增一個欄位,用來判斷使用者是前進還是後退以及是否需要 keep-alive

(2)實現

  • 首先我們需要在的meta物件裡定義兩個值:
    1. keepAlive:這個路由是否需要快取
    2. deepth:深度,也就是頁面之間的前進後退的層次關係
  // 首頁
  {
    path: '*',
    name: 'Home',
    // 路由懶載入:
    // webpackPreload:
    component: () => import(/* webpackPreload: true */ '@/views/home'),
    meta: {
      keepAlive: true,
      deepth: 1
    }
  },
  // 商品列表
  {
    path: '/product',
    name: 'Product',
    component: () => import('@/views/product'),
    meta: {
      keepAlive: true,
      deepth: 2
    }
  },
  // 商品詳情
  {
    path: '/detail',
    name: 'Detail',
    component: () => import('@/views/detail'),
    meta: {
      keepAlive: true,
      deepth: 3
    }
  },
  • 然後我們在中根據 meta 物件定義一下:
<template>
  <div id="app">
    <keep-alive :include="include">
      <router-view v-if="$route.meta.keepAlive" />
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive" />
  </div>
</template>
  • 最後我們需要實時的監聽路由:
export default {
  data() {
    return {
      include: []
    };
  },
  watch: {
    $route(to, from) {
      // 如果要to(進入)的頁面是需要keepAlive快取的,把name push進include陣列中
      if (to.meta.keepAlive) {
        !this.include.includes(to.name) && this.include.push(to.name);
      }
      // 如果 要 form(離開) 的頁面是 keepAlive快取的,
      // 再根據 deepth 來判斷是前進還是後退
      // 如果是後退:
      if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
        const index = this.include.indexOf(from.name);
        index !== -1 && this.include.splice(index, 1);
      }
    }
  }
};
  • 上面這個就是大佬所實現的主要步驟,一共其實就兩步:設定meta監聽路由並判斷。這裡有一定要注意的是:你的路由中定義的 name 和頁面中定義的 name 一定要全等,並區分大小寫!!!
 // router.js
{
    path: '*',
    name: 'Home', // name要大小寫要一致
    component: () => import(/ '@/views/home'),
    meta: {
      keepAlive: true,
      deepth: 1
    }
}

// home.vue
export default {
    name: 'Home', // name要大小寫要一致
}

3、hack 手法

(1)問題

  • 從上面我們可以看到,其實設定起來還是挺嚴格的,就拿name一致來說,如果團隊裡面大家從一開始就都定義了一個規範那還好說,但是往往大家就name保持一致這個就可能很難。

(2)實現

  • 所以我們可以這樣設定,首先我們肯定還是要利用meta.keeAlive欄位來進行判斷的,但是不用定義deepth深度了。
  // 首頁
  {
    path: '*',
    name: 'Home',
    component: () => import('@/views/home'),
    meta: {
      keepAlive: true
    }
  },
  // 商品列表
  {
    path: '/product',
    name: 'Product',
    component: () => import('@/views/product'),
    meta: {
      keepAlive: true
    }
  },
  // 商品詳情
  {
    path: '/detail',
    name: 'Detail',
    component: () => import('@/views/detail'),
    meta: {
      keepAlive: true
    }
  },
  • 進入到頁面中我們為<router-view>新增一個key,這個key就像是我們使用v-for迴圈所定義的一樣,大家都知道,key的作用就是一個標識對吧,作用於vue在虛擬 dom 進行diff演算法,提高渲染效率。
<template>
  <div id="app">
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive" :key="key" />
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive" :key="key" />
  </div>
</template>

<script>
  export default {
    computed: {
      key() {
        return this.$route.fullPath;
      }
    }
  };
</script>
  • 然後我們對其需要強制重新整理的頁面引數里加個時間戳,這樣就可以實現按需keep-alive了。
  onClick() {
      this.$router.push({
        path: '/product',
        query: {
          t: +new Date()
        }
      })
  }

3、小結

  • 兩者相比,我覺得可能第二種更加的實用,比一種簡單,但是有醜,因為會帶串時間戳字串如:
  • 第一種算是比較完美,其實設定起來也不難,只是對團隊人員的規範性要求比較高。
  • 我們專案中使用第二種方案,大家可以根據自己的背景任意選擇一種方案,或者有更好的方案可以留言一起學習學習,

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4289/viewspace-2825165/,如需轉載,請註明出處,否則將追究法律責任。

相關文章