著者:Mai Le出典:https ://developer.hs.net/thread/2159
必要
一時停止および再生機能を備えたプログレスバーを実装します。レンダリングはおおよそ次のとおりです。
機能はそれほど複雑ではなく、技術的な問題も感じません。まず、タイマーを使ってこの機能を実現することを考えました。ボタンでタイマーの開始と一時停止を制御できます。次に、 vueは最初のバージョンを実現するために使用されます。
タイマーの実装
コードは次のように表示されます。
<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;
}
},
再生ボタンをクリックすると、ページがスタックし、再生が遅くなっていることがわかります。
最適化1
cssアニメーションを使用します。
<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兄弟があります(つまり、要素は複合レイヤーの上にレンダリングされます)