まずプロジェクトの要件を確認します
勤勉なフロントエンド開発者として、私たちはプロダクト マネージャーによって提起されるさまざまなニーズに常に直面しなければなりません。たとえば、次の写真のシーンがあります。
シーン:
ホームページからナビゲーションをクリックしてリストページに入ります。
リストページ リストをクリックしてデータ詳細ページに移動します
詳細ページから戻ると、リスト ページがキャッシュされ、データが再レンダリングされなくなり、ユーザー エクスペリエンスが向上することが期待されます。
分析する
この要件では、小規模プログラムの場合、デフォルトのリスト ページがキャッシュされます。小規模プログラムの実行環境は 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...ついに解決しました、完璧です!