最近接到一個需求蜻懦,實(shí)現(xiàn)起來很簡單甜癞,但是考慮到性能問題,需要花一些技巧宛乃。
頁面性能優(yōu)化悠咱,分別應(yīng)用到:
事件委托蒸辆、動態(tài)數(shù)組、懶加載析既、緩存躬贡、節(jié)流防抖
場景和需求:
移動端一個圖庫列表頁,幾百張甚至幾千張圖片的列表展示
點(diǎn)擊其中的一張圖片眼坏,可以預(yù)覽大圖拂玻,左右切換查看所有其他圖片的大圖
- 第一部分:
問題:點(diǎn)擊事件,如果每張圖的標(biāo)簽都綁定了事件宰译,在移動端檐蚜,性能很糟糕。
解決辦法:事件委托沿侈。
HTML結(jié)構(gòu):
<ul class="photo-items" @click="previewPhoto" id='photo-list'>
<li v-for="(item,index) in items" class="photo-item" :data-index="index">
<img :src="item.srcUrl"/>
</li>
</ul>
previewPhoto(ev){
let oUl = document.getElementById('photo-list');
let ev = ev || window.event;
let target = ev.target || ev.srcElement;
while(target !== oUl ){
//遞歸調(diào)用闯第,使當(dāng)前點(diǎn)擊對象指定到li上
if(target.tagName.toLowerCase() == 'li'){
const index = parseInt(target.dataset.index)
break;
}
target = target.parentNode;
}
},
事件委托參考文章:https://www.cnblogs.com/liugang-vip/p/5616484.html
- 第二部分:
問題:使用swiper,左右切換圖片缀拭,
如果需要查看幾百張圖片咳短,就要生成幾百個swiper-slide,對性能來說也是一件很糟糕的事情智厌。
如圖:
解決辦法:使渲染swiper的數(shù)組永遠(yuǎn)只有三張圖片诲泌,每次切換盲赊,根據(jù)索引讓數(shù)組的三張圖片變一次铣鹏。
<swiper :options="swiperOption" ref="mySwiper" >
<swiper-slide v-for="(item,index) in swiperList" :key="index">
<img :src="item.srcUrl"/>
</swiper-slide>
</swiper>
computed: {
swiperPicList(){
if(this.items.length > 0){ //圖片數(shù)組如果不為空
//curIndex表示當(dāng)前查看的圖片索引
if(this.curIndex == 0){ //當(dāng)前圖片為第一張時候,返回的數(shù)組
return [
{srcUrl: this.items[this.curIndex].srcUrl},
{srcUrl: this.items[this.curIndex + 1].srcUrl},
]
}else if(this.curIndex == (this.items.length - 1)){ //當(dāng)前圖片為最后一張時候哀蘑,返回的數(shù)組
return [
{srcUrl: this.items[this.curIndex-2].srcUrl},
{srcUrl: this.items[this.curIndex-1].srcUrl},
{srcUrl: this.items[this.curIndex].srcUrl},
]
}else{
return [
{srcUrl: this.items[this.curIndex - 1].srcUrl},
{srcUrl: this.items[this.curIndex].srcUrl},
{srcUrl: this.items[this.curIndex + 1].srcUrl},
]
}
}
},
}
為什么是三張圖诚卸?
因?yàn)閟wiper,有兩個屬性绘迁,當(dāng)滑動到第一張的時候isBeginning為true合溺,這可以當(dāng)做用戶向左滑的判斷,當(dāng)滑動到最后一張的時候isEnd為true缀台,同理可以當(dāng)做用戶向右滑動的判斷棠赛。
[
{srcUrl: this.items[this.curIndex - 1].srcUrl},//當(dāng)前圖片前一張
{srcUrl: this.items[this.curIndex].srcUrl},//當(dāng)前圖片
{srcUrl: this.items[this.curIndex + 1].srcUrl},//當(dāng)前圖片后一張
]
然后使當(dāng)前索引的圖片永遠(yuǎn)在數(shù)組swiperPicList中間,
1膛腐、向左滑動的時候睛约,curIndex--,向右滑動的時候 curIndex++
但是對于swiper中間選中項(xiàng)向左滑到第一張哲身,第一張會變成選中項(xiàng)辩涝,用戶看到的其實(shí)是數(shù)組第一張圖。向右同理勘天。
所以需要使用swiper方法this.swiper.slideTo(1,0, false)怔揩,使得每次滑動之后捉邢,swiper都切換到第二個為選中項(xiàng),這樣用戶看到是就是數(shù)組的中間項(xiàng)商膊。
參考API:
mySwiper.slideTo(index, speed, runCallbacks)
Swiper切換到指定slide伏伐。
index:必選,num晕拆,指定將要切換到的slide的索引秘案。
speed:可選,num(單位ms)潦匈,切換速度
runCallbacks: 可選阱高,boolean,設(shè)置為false時不會觸發(fā)transition回調(diào)函數(shù)茬缩。
除了是第一張和最后一張的時候做特殊處理赤惊。
watch:{
curIndex(curIndex){
if(curIndex == 0){
//當(dāng)滑動到第一張圖片的時候,返回的數(shù)組是兩張圖凰锡,
//slideTo的index應(yīng)該為0未舟,跳轉(zhuǎn)到第一張圖。
this.swiper.slideTo(0,0, false);
}else if (this.curIndex == (this.items.length-1)){
//當(dāng)滑動到最后一張圖片的時候掂为,返回數(shù)組是三張圖
//slideTo的index應(yīng)該為2裕膀,跳轉(zhuǎn)到第三張圖。
this.swiper.slideTo(2,10, false);
}else {
this.swiper.slideTo(1,0, false);
//其他索引的圖片都是跳到第二張圖
}
}
},
computed: {
swiper() {
return this.$refs.mySwiper.swiper
},
swiperOption(){
let _this = this // _this為VUE實(shí)例勇哗,要特別注意
return {
initialSlide :1,
on: {
//滑動事件
//on事件里面的this指向swiper實(shí)例昼扛,要特別注意
transitionEnd: function(){
//isEnd為true,表示用戶向右滑動
if(this.isEnd){
if(_this.curIndex < (_this.items.length-1)){
_this.curIndex = _this.curIndex + 1
}
}
//isBeginning為true欲诺,表示用戶向左滑動
if(this.isBeginning){
if(_this.curIndex >= 1){
_this.curIndex = _this.curIndex - 1
}
}
//這里做的是特殊處理抄谐,
// 因?yàn)楫?dāng)前圖片為最后一張時候,選中的圖片為第三張扰法,
//swiperPicList數(shù)組中也是第三張蛹含,
//最后一張滑動的方向只有向左,所以_this.curIndex - 1
//做這個處理是最后一張向左滑動因?yàn)榉祷財?shù)組的原因塞颁,不能用isBeginning來判斷
if(_this.curIndex == (_this.items.length-1)){
_this.curIndex = _this.curIndex - 1
}
},
}
}
},
}
最終效果
初衷是想讓swiper不需要渲染所有的圖片浦箱,臨時做一個小數(shù)組,每次切換祠锣,小數(shù)組都是動態(tài)的獲取相鄰的三張照片酷窥,可能不是最優(yōu)的方法,創(chuàng)建數(shù)組也可以進(jìn)行再封裝锤岸。
以上只是傳達(dá)一個優(yōu)化思想
swiper參考文檔:https://www.swiper.com.cn/api/methods/109.html
- 第三部分:
問題:圖片列表竖幔,頁面上幾百上千張圖片,用戶訪問頁面是偷,要拉很長時間拳氢,還要考慮用戶在頁面來回滾動的情況
一募逞、圖片多,要拉很長時間
①馋评、懶加載放接,這個很簡單。
②留特、緩存纠脾,這個也很簡單。
二蜕青、考慮到用戶在頁面上下來回滾動
③苟蹈、節(jié)流防抖
節(jié)流:在頻繁觸發(fā)的情況下,按照一定的時間去執(zhí)行右核。
//聲明一個變量當(dāng)標(biāo)志位慧脱,記錄當(dāng)前代碼是否在執(zhí)行
const Throttling = (fn,intelval) => {
let time = null;
return function (){
if(!time){
time = setTimeout(() => {
fn.call(this,arguments)
time = null
},intelval)
}
}
}
防抖:在頻繁觸發(fā)的情況下,只有足夠的空閑時間贺喝,才執(zhí)行一次菱鸥。
//setTimeout做緩存池
const Throttling = (fn,delay) => {
let time;
return function (){
if(time) clearTimeout(time)
time = setTimeout(() => {
fn.call(this,arguments)
},delay)
}
}