プログレスバーを最適化するNの方法

著者:Mai Le出典:https ://developer.hs.net/thread/2159

必要

一時停止および再生機能を備えたプログレスバーを実装します。レンダリングはおおよそ次のとおりです。

2.png

機能はそれほど複雑ではなく、技術的な問題も感じません。まず、タイマーを使ってこの機能を実現することを考えました。ボタンでタイマーの開始と一時停止を制御できます。次に、 vueは最初のバージョンを実現するために使用されます。

タイマーの実装

コードは次のように表示されます。

3FA276AD-57A3-45CD-925C-8BDB48DD414D.png

<script>
let timer, totalTime = 3000;
export default {
  name: "Progress",
	data() {
		return {
			isPlay: false,
			progress: 0
		}
	},

	methods: {
		run() {
			timer = setInterval(() => {
				const {progress} = this;
				this.progress = progress + 2;
				if(this.progress === 100) {
					this.cancel();
				}
			}, 3000/ 100)
		},
		cancel() {
			clearInterval(timer);
			timer = null;
		},
		changePlay() {
			const { isPlay } = this;
			this.isPlay = !isPlay;
			if(this.isPlay) {
				this.run();
			} else {
				this.cancel();
			}
		},
		replay() {
			this.isPlay = true;
			this.progress = 0;
			this.run();
		}
	}
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
	.g-contain {
		width: 240px;
		height: 25px;
		border-radius: 25px;
		background: #eee;
		overflow: hidden;
}
	.g-progress {
		height: inherit;
		border-radius: 25px 0 0 25px;
		background: #0f0;
	}
</style>

タイマーを介して変数を急速に増分する進行状況の増加を実現するprogressために、変数を変更するたびに、ビューが再計算およびレンダリングされ、ページ全体が継続的に再作成および再描画されます。プロジェクトがそれほど複雑でなければ、問題はそれほど大きくないようです。大規模なプロジェクトや、ページ上に多数のDOMノードがあるプロジェクトに遭遇すると、明らかに遅れを感じるでしょう。

テスト:

ページに1億個の要素を追加し、

data() {
		return {
			isPlay: false,
			progress: 0,
			arr: []
		}
	},
	created() {
		for(let i = 0; i < 100000; i ++) {
			this.arr[i] = i;
		}
	},

1647681376897.jpg

再生ボタンをクリックすると、ページがスタックし、再生が遅くなっていることがわかります。

最適化1

cssアニメーションを使用します。

4DC90A53-ECAC-48F7-8F99-BD4A6DE0C50D.png

<script>
export default {
  name: "Progress",
	data() {
		return {
			isPlay: false,
			type: 0, // 0播放, 1 重播
			totalTime: 2
		}
	},
	methods: {
		end(){},

		changePlay() {
			const { isPlay } = this;
			this.isPlay = !isPlay;
		},
		replay() {
			const { type } = this;
			this.isPlay = true;
			this.type = type ? 0 : 1;
		}
	}
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
	@keyframes play { 
    to {width: 100%}  
	}

	@keyframes replay {
    to {width: 100%}  
	}
	.g-contain {
		width: 240px;
		height: 25px;
		border-radius: 25px;
		background: #eee;
		overflow: hidden;
}
	.g-progress {
		width: 0;
		height: inherit;
		border-radius: 25px 0 0 25px;
		background: #0f0;
		/* animation-timing-function: linear; */
		-webkit-animation-timing-function: linear;
	}
	.g-progress.play {
		animation: play 3s infinite linear;
	}
	.g-progress.replay {
		animation: replay 3s infinite linear;
	}
	.g-progress.animationplay {     /* 使animation动画启动 */
		animation-play-state: running;
    -webkit-animation-play-state: running;
	}

	.g-progress.animationpause {    /* 使animation动画暂停 */
		animation-play-state: paused;
		-webkit-animation-play-state: paused;
	}
</style>

CSS3キーフレームアニメーションを使用してプログレスバーの変更を制御すると、多くの計算が削減され、パフォーマンスの消費がある程度削減されます。

ただし、この方法でも、ページ全体のリフローと再描画が頻繁にトリガーされます。

ロングリストコンポーネントをレンダリングして、効果を確認します。

List.vue

<template>
	<ul>
		<li v-for="(i, index) in arr" :key="index">{{i}}</li>
	</ul>
</template>

<script>
export default {
  name: "List",
	data() {
		return {
			arr: []
		}
	},
	created() {
		for(let i = 0; i < 100000; i ++) {
			this.arr[i] = i;
		}
	}
};
</script>


以下を使用して登録を導入します。

import List from './List.vue'
components: {
    List
  },

再生プロセス中、フリーズもありますが、以前のソリューションよりも優れています。ここで結果を確認するのは便利ではありません。最後に、ダウンロードしてテストできるコードが添付されています。

最適化2

CSSアニメーションを使用してGPUアクセラレーションを有効にします。GPUは主に3Dレンダリングとハードウェアアクセラレーションを担当します。

このソリューションには、最適化1のロジックとページ構造に違いはありません。違いは、次のスタイルにあります。

<style scoped>
@keyframes play { 
    0% {  
      transform: translateX(-50%) scaleX(0);  /* 用 scaleX 来代替 width */
    }
    to {
	transform: translateX(0) scaleX(1);
    }
}
@keyframes replay {
    0% {  
      transform: translateX(-50%) scaleX(0);  /* 用 scaleX 来代替 width */
    }
		to {
					transform: translateX(0) scaleX(1);
		} 
	}
	.g-contain {
		width: 240px;
		height: 25px;
		border-radius: 25px;
		background: #eee;
		overflow: hidden;
}
	.g-progress {
		width: 100%;
		height: inherit;
		border-radius: 25px 0 0 25px;
		background: #0f0;
                will-change: transform; /**通知浏览器提前过好优化 */ 
		animation-timing-function: linear;
		-webkit-animation-timing-function: linear;
	}
	.g-progress.play {
		animation: play 3s infinite linear;
	}
	.g-progress.replay {
		animation: replay 3s infinite linear;
	}
	.g-progress.animationplay {     /* 使animation动画启动 */
		animation-play-state: running;
    -webkit-animation-play-state: running;
	}

	.g-progress.animationpause {    /* 使animation动画暂停 */
		animation-play-state: paused;
		-webkit-animation-play-state: paused;
	}
</style>


will-change:transformを使用します;/**事前に最適化するようにブラウザに通知します*/

変換を使用してGPUアクセラレーションを有効にします。

リストコンポーネントを入力してテストすると、ページの明らかなラグがなくなっていることがわかります。

要約:

アニメーションを使用する場合、ページにさまざまな複合レイヤーを形成させることで、パフォーマンスを最適化できます。

開く方法:

  • 3Dまたはパースペクティブ変換CSSプロパティ
  • 加速ビデオデコードを使用する要素video>には3Dがあります
  • (WebGL)コンテキストまたは高速化された2Dコンテキストcanvas要素
  • ハイブリッドプラグイン(Flashなど)
  • CSSを使用して不透明度をアニメーション化するか、アニメーション化された変換要素を使用します(以前のブラウザーでは、このメソッドでも再描画と再配置が発生します)
  • 加速されたCSSフィルターを備えた要素
  • 要素には、複合レイヤーを含む子孫ノードがあります(つまり、要素には、それ自体のレイヤーにある子要素があります)
  • 要素には、複合レイヤーを含む低いz-index兄弟があります(つまり、要素は複合レイヤーの上にレンダリングされます)

Github

{{o.name}}
{{m.name}}

おすすめ

転載: my.oschina.net/u/3620858/blog/5495612