Vue コンポーネント キャッシュのキープアライブの正しい使用姿勢

まずプロジェクトの要件を確認します

勤勉なフロントエンド開発者として、私たちはプロダクト マネージャーによって提起されるさまざまなニーズに常に直面しなければなりません。たとえば、次の写真のシーンがあります。

シーン:

ホームページからナビゲーションをクリックしてリストページに入ります。

リストページ リストをクリックしてデータ詳細ページに移動します

詳細ページから戻ると、リスト ページがキャッシュされ、データが再レンダリングされなくなり、ユーザー エクスペリエンスが向上することが期待されます。

分析する

この要件では、小規模プログラムの場合、デフォルトのリスト ページがキャッシュされます。小規模プログラムの実行環境は WeChat クライアントであるため、ページを開くと新しい Web ビューが作成されます。

すべてのリスト ページと詳細ページは 2 つの Web ビューです。詳細ページに入ると、リスト ページの Web ビューは詳細ページの Web ビューの下にのみ配置され、破棄されません。

アプレットの動作環境は以下の通りです。 各ページにWebViewがあることがわかります。

写真

ただし、このプロジェクトは Vue で開発された Web アプリです。複数のコンポーネントが 1 つのウィンドウを共有します。ルートを切り替えると、ルート コンポーネントはルートを切り替えるときに破棄されます。リスト ページは、詳細ページに入るときにすべて破棄されます。リストに戻るページ、リスト ページコンポーネントが再ロードされます。

写真

解決

1. 寝間着が必要な人、シンプルな需要に変える

うーん…、鏡で自分を見た、この人生では自分の顔から何の便宜も得られないかもしれない、だから正直に計画を変更しましょう。

写真

それがキープアライブです

keep-aliveこれは Vue によって提供される抽象コンポーネントであり、主にコンポーネントの状態を保存したり、再レンダリングを回避したりするために使用されます。

<keep-alive> 動的コンポーネントをラップすると、非アクティブなコンポーネントのインスタンスは破棄されずにキャッシュされます。

と同様<transition> に、 <keep-alive> それ自体では DOM 要素をレンダリングせず、親コンポーネントのチェーンにも表示されない抽象コンポーネントです。

ただし、 keep-alive それによってラップされたすべてのコンポーネントはキャッシュされます。

em... どうすればいいのか、リストページをキャッシュさせるだけです。

分析する

要件を 2 つのステップに分割できます

(1) キャッシュが必要なコンポーネントとキャッシュする必要のないコンポーネントを区別し、コンポーネントのルーティング設定のメタ情報にキャッシュする必要のあるコンポーネントとキャッシュする必要のないコンポーネントを定義します。

写真

具体的なコードは以下の通り

1. 2 つのアウトレットを定義します router-view

<keep-alive>
    <!-- 需要缓存的视图组件 -->
  <router-view v-if="$route.meta.keepAlive">
  </router-view>
</keep-alive>

<!-- 不需要缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive">
</router-view>

2. ルータ設定でどれをキャッシュする必要があるか、どれをキャッシュする必要がないかを定義します。

new Router({
    routes: [
        {
            path: '/',
            name: 'index',
            component: () => import('./views/keep-alive/index.vue')
        },
        {
            path: '/list',
            name: 'list',
            component: () => import('./views/keep-alive/list.vue'),
            meta: {
                keepAlive: true //需要被缓存
            }
        },
        {
            path: '/detail',
            name: 'detail',
            component: () => import('./views/keep-alive/detail.vue')
        }
    ]
})

オンデマンドでコンポーネントのキャッシュを開始する

公式ドキュメントで提供されている API から始めます。

キープアライブ コンポーネントがインクルードに設定されている場合、インクルードに一致するコンポーネントのみがキャッシュされます。

したがって、インクルード配列を動的に変更してオンデマンド キャッシュを実現するという考え方です。

<template>
    <keep-alive :include="include">
        <!-- 需要缓存的视图组件 -->
      <router-view v-if="$route.meta.keepAlive">
      </router-view>
    </keep-alive>

    <!-- 不需要缓存的视图组件 -->
    <router-view v-if="!$route.meta.keepAlive">
    </router-view>
</template>
<script>
    export default {
      name: "app",
      data: () => ({
        include: []
      }),
      watch: {
        $route(to, from) {
          //如果 要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 include数组
          if (to.meta.keepAlive) {
            !this.include.includes(to.name) && this.include.push(to.name);
          }
        }
      }
    };
</script>

この時、詳細ページから一覧ページに戻ると本当に一覧ページが更新されなくなっていることが分かりました

写真

em... リスト ページがキャッシュされたため、また新しい問題が発生しました。このとき、ホームページから特定のリストに入ろうとクリックしたのですが、更新されませんでした。終了したら、ホームページのナビゲーションをクリックすると、別のリスト ページを入力してください。また、言い換えると、ホームページからリスト コンポーネントを入力した場合も、キャッシュされるべきではありません。

写真

これを解決するには、ルートを定義するときに、メタ情報に別のフィールドを追加します。これは、受信ルートのレベルを表す深さフィールドです。たとえば、ホームページのルートの深さは 0.5、リスト ページは 1、詳細ページは2です

new Router({
    routes: [
        {
            path: '/',
            name: 'index',
            component: () => import('./views/keep-alive/index.vue'),
            meta: {
                deepth: 0.5 // 定义路由的层级
            }
        },
        {
            path: '/list',
            name: 'list',
            component: () => import('./views/keep-alive/list.vue'),
            meta: {
                deepth: 1
                keepAlive: true //需要被缓存
            }
        },
        {
            path: '/detail',
            name: 'detail',
            component: () => import('./views/keep-alive/detail.vue'),
            meta: {
                deepth: 2
           }
        }
    ]
})

次に、app.vue にリスナーを追加して、ルートに入る方向をリッスンします。

具体的なコードは以下の通り

<template>
    <keep-alive :include="include">
    <!-- 需要缓存的视图组件 -->
      <router-view v-if="$route.meta.keepAlive">
      </router-view>
    </keep-alive>

    <!-- 不需要缓存的视图组件 -->
    <router-view v-if="!$route.meta.keepAlive">
    </router-view>
</template>
<script>
    export default {
      name: "app",
      data: () => ({
        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) {
            var index = this.include.indexOf(from.name);
            index !== -1 && this.include.splice(index, 1);
          }
        }
      }
    };
</script>

em...ついに解決しました、完璧です!

写真

おすすめ

転載: blog.csdn.net/sdasadasds/article/details/132076853