記事ディレクトリ
Vue 使用時の一般的なパフォーマンスの最適化
1、v-if の同時使用を避けるための v-for トラバーサル
Vue2 ではv-for
優先度が高いため、コンパイル プロセス中にすべてのリスト要素が走査されて仮想 DOM が生成され、v-if によってレンダリングが判断されます。冗長な論理判断が発生し、パフォーマンスが無駄になります。最も重要なことは、条件を満たさない仮想 DOM を生成しないことです。
1、リスト内の項目をフィルタリングするため ( 比如 v-for="user in users" v-if="user.isActive"
)。この場合、ユーザーは、フィルター処理されたリストを返す計算されたプロパティまたはメソッド (activeUsers など) に置き換えることができます。
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{
{
user.name }}
</li>
</ul>
methods:{
// 方法
activeUsers(){
//在这里面处理需要显示的数据 然后返回筛选过的列表
}
}
2. 非表示にする必要があるリストのレンダリングを避けるため ( 比如 v-for="user in users" v-if="shouldShowUsers"
)。この場合、v-if をコンテナ要素 (例: ul、ol) に移動します。
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{
{
user.name }}
</li>
</ul>
Vue3v-if
では優先順位が高く、判定条件が v-for で巡回するリスト内の属性である場合、v-if は取得できません。
注意
: 同じ要素に対して v-if と v-for を同時に使用しないでください。
2. v-for を使用してイベントを各要素にバインドする必要がある場合は、イベント プロキシ** を使用できます。
イベント委任の本質は、親要素へのイベントのバブリング機能を使用することです。この方法では、次のようにループ内の各ノードにイベントを追加する必要がなくなります。
親要素 ul にクリック イベントを追加します。パラメータを渡す必要がある場合は、以下の id 属性などのカスタム属性を追加するだけです。
<!-- 使用事件委托进行处理和传参 添加自定义属性id -->
<ul class="weekdays" @click="debounce($event)">
<li v-for="(item, index) in dayList" :key="index" :id="index" >{
{
item.day }}</li>
</ul>
// 事件委托处理
debounce(event) {
if (event.target && event.target.nodeName == "LI") {
// 现在就可以拿到当前的节点 所以就能拿到里面的属性和数据
console.log("我点击的是:", event.target);
}
},
イベント プロキシには 2 つの利点があります
: 1. イベント ハンドラーを親ノードにプロキシして、メモリ使用量を削減します;
2. 子ノードを動的に生成するときに、イベント ハンドラーを親ノードに自動的にバインドします。
3. 一部のデータが応答しない
会員リストや製品リストなど、一部のデータは応答性がありませんが、純粋なデータ表示のみです。動的な変更が存在しないシナリオでは、データに対して応答性の高い処理を実行する必要がないため、データの表示が大幅に向上します。レンダリング速度。
Object.freeze()
メソッドを使用してオブジェクトをフリーズできますが、このメソッドによってフリーズされたオブジェクトは変更できません。つまり、このオブジェクトに新しいプロパティを追加したり、既存のプロパティを削除したり、既存のプロパティの列挙可能性、構成可能性、書き込み可能性を変更したりすることはできません。オブジェクトのプロパティの値を変更することはできず、既存のプロパティの値を変更することはできません。また、オブジェクトのプロトタイプを変更することもできません。
export default {
data: () => ({
userList: []
}),
async created() {
const users = await axios.get("/api/users");
this.userList = Object.freeze(users);
}
};
Vue2 のレスポンシブ ソース コード アドレス:src/core/observer/index.js - 144行
次のようなものです。
export function defineReactive (...){
// getOwnPropertyDescriptor 返回指定对象上一个自有属性对应的属性描述符
// 也就是直接赋予该对象的属性,不需要从原型链上进行查找的属性
const property = Object.getOwnPropertyDescriptor(obj, key)
判断configurable` 为 `false`不做处理
if (property && property.configurable === false) {
return
}
...
}
冒頭で判定したダイレクトリターンは応答処理を行っていないことconfigurable
が分かります。false
configurable` 为 `false` 表示这个属性是不能被修改的,而冻结的对象的 `configurable` 就是为 `false
これは、Vue が通常データ内で定義するデータであり、次のすべての属性に get 属性と set 属性を可能な限り自動的に追加します。
开始冻结对象
:
freList はリクエスト バックエンドのリスト データです。
created() {
this.dayList = Object.freeze(freList)
console.log("daylist:",this.dayList);
},
get 属性と set 属性がないことがわかりますが、同時にこれらのデータは応答しません。
4. 一部のページではkeep-alive
キャッシュ コンポーネントが使用されています
列表页>详情页>列表页
例えば、フォーム入力ページが次のステップに入った後、前のステップのフォームページに戻った後、前後にジャンプするシーンなど、フォーム入力の内容が保持される必要があります。
基本的な使い方:
如果需要缓存整个项目,则如下设置(直接包裹根router-view即可):
<keep-alive>
<router-view> </router-view>
</keep-alive>
缓存部分页面或者组件,使用route.meta属性
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
注:<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
<keep-alive>
<component :is="view"></component>
</keep-alive>
注: keepAlive で構成されたページは、再入力しても再レンダリングされません (最初に入ったときにすべてのフック関数がトリガーされます)。また、このページ内のコンポーネントも同じ方法では再レンダリングされません。
また、これにより、コンポーネント内の関連操作 (親コンポーネントと子コンポーネントの間で値を渡すなど、毎回ページを再レンダリングする必要がある操作) が無効になる可能性があります。これにより、説明不能で検証不可能なバグが発生する可能性があります。
Vue2.1.0 では、コンポーネントの条件付きキャッシュを可能にする include 属性と exclude 属性が追加されました。どちらも、カンマ区切りの文字列、正規表現、または配列として表すことができます。
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正则表达式 (需要 `v-bind`绑定) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- 数组 (需要 `v-bind`绑定) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
注: 照合では、最初にコンポーネント自体の名前オプションがチェックされ、名前オプションが使用できない場合は、ローカルに登録された名前 (親コンポーネントのコンポーネント オプションのキー値) と照合されます。匿名コンポーネントは照合できません。
動的判断、v-bind:includeを使用
<keep-alive :include="includedComponents">
<router-view></router-view>
</keep-alive>
includedComponents动态设置即可
インターセプト処理には beforeRouteLeave または afterEach を使用します
如在项目在Category组件中的设置:
beforeRouteLeave(to,from,next){
if(to.name=='DemoIndex'){
if(!from.meta.keepAlive){
from.meta.keepAlive=true
}
next()
}else{
from.meta.keepAlive=false
to.meta.keepAlive=false
next()
}
},
在beforeRouteLeave中to.name根据具体的路由进行动态缓存设置
keepAlive を使用した後のライフ サイクルの変更 (重要):
初めてキャッシュ ページに入る: beforeRouteEnter --> 作成 --> マウント --> アクティブ化 --> 非アクティブ化
再度キャッシュ ページに入る: beforeRouteEnter --> アクティブ化 --> 非アクティブ化
注:
1. ページがキャッシュされると、作成、マウントなどのライフ サイクルが無効になるため、ここでアクティブ化すると非常に便利です。いくつかの操作を実行したい場合は、アクティブ化した状態で完了することができます (次のようにすると栗が表示されます:リスト ページは先頭に戻ります (2 番目の閲覧位置)
2. アクティブ化されたキープアライブ コンポーネントはアクティブ化されたときに呼び出され、このフックはサーバー側のレンダリング中には呼び出されません。
3. 非アクティブ化されたキープアライブ コンポーネントは非アクティブ化されたときに呼び出されますが、このフックはサーバー側のレンダリング中には呼び出されません。
5. サードパーティの UI ライブラリをオンデマンドでインポートする
たとえば、element-ui ライブラリのオンデマンド導入である vantUi については、この記事を参照してください。
6. リストデータの遅延ロードとページングデータのスライディングロード
リストデータの遅延読み込みスクロールバーは、スクロールバーを一番下までスクロールすると次のページのデータをリクエストし始めます。手ぶれ補正機能と併用すると、一瞬でリクエストが多すぎるのを防ぐことができます。
如下代码
:
ここでは vue3 を使用して記述しています。vue2 はノードを取得する方法が異なるだけで、他はすべて同じです。
onMounted(() => {
// 获取滚动容器的节点
let containerEle = showContentEl.value;
if (!containerEle) return;
// 监听滚动条
containerEle.addEventListener("scroll", function () {
const clientHeight = containerEle.clientHeight;
const scrollTop = parseInt(containerEle.scrollTop);
const scrollHeight = containerEle.scrollHeight;
// 判断是否滚动条是否滚动到底 (-1是为了控制误差)
if (clientHeight + scrollTop >= scrollHeight - 1) {
// 开始防抖请求数据
debounceLoadMaterialList();
}
});
});
<template>
<div class="container">
<div class="list">
展示的列表数据
</div>
</div>
</template>
インターフェイスの手ぶれ補正を設定します。
import * as _ from "lodash";
// 设置接口防抖
const debounceLoadMaterialList = _.debounce(loadMaterialList, 500);
7. 変数のローカリゼーション
this.xx
簡単に言えば、アクセスするたびに、応答性の高いオブジェクトなので毎回トリガーされ、getter
コレクションに依存する関連コードを実行するため、何度も参照される変数を保存することです。より多くの変数を使用すると、パフォーマンスは自然に向上します。
要件の観点から見ると、関数内の変数に対して依存関係の収集を実行するだけで十分ですが、多くの人は習慣的にプロジェクト内で多くのことを書き、バックグラウンドで行われていることを無視しており、これがパフォーマンスの問題につながりthis.xx
ますthis.xx
。
比如下面vue2的例子
:
<template>
<div :style="{ opacity: number / 100 }"> {
{
result }}</div>
</template>
<script>
import {
someThing } from '@/utils'
export default {
props: ['number'],
computed: {
base () {
return 100 },
result () {
let base = this.base, number = this.number // 保存起来 -- 变量本地化
for (let i = 0; i < 1000; i++) {
number += someThing(base) // 避免频繁引用 this.xx
}
return number
}
}
}
</script>
8. イベントの破棄
Vue コンポーネントが破棄されると、そのすべての命令とイベント リスナーは自動的にバインド解除されますが、コンポーネント自体のイベントにのみ制限されます。
定时器
登録されたリスナーなどの場合はaddEventListener
、メモリ リークを避けるために、手動で破棄するか、コンポーネント破棄のライフサイクル フックでバインドを解除する必要があります。
<script>
export default {
created() {
this.timer = setInterval(this.refresh, 2000)
addEventListener('touchmove', this.touchmove, false)
},
beforeDestroy() {
clearInterval(this.timer)
this.timer = null
removeEventListener('touchmove', this.touchmove, false)
}
}
</script>