【小技巧】基于vue+swiper实现图片库列表点击查看大图,可左右切换(事件委托、动态数组、懒加载、缓存、节流防抖)

最近接到一个需求,实现起来很简单,但是考虑到性能问题,需要花一些技巧。

页面性能优化,分别应用到:
事件委托、动态数组、懒加载、缓存、节流防抖

场景和需求:
移动端一个图库列表页,几百张甚至几千张图片的列表展示
点击其中的一张图片,可以预览大图,左右切换查看所有其他图片的大图

- 第一部分:

问题:点击事件,如果每张图的标签都绑定了事件,在移动端,性能很糟糕。

解决办法:事件委托。

HTML结构:

<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 ){
        //递归调用,使当前点击对象指定到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,对性能来说也是一件很糟糕的事情。

如图:


image.png

解决办法:使渲染swiper的数组永远只有三张图片,每次切换,根据索引让数组的三张图片变一次。

<swiper :options="swiperOption" ref="mySwiper" >
        <swiper-slide  v-for="(item,index) in swiperList" :key="index">
             <img :src="item.srcUrl"/>
        </swiper-slide>
</swiper>
image.png
computed: {
  swiperPicList(){
   if(this.items.length > 0){  //图片数组如果不为空
        //curIndex表示当前查看的图片索引
        if(this.curIndex == 0){  //当前图片为第一张时候,返回的数组
            return [
               {srcUrl: this.items[this.curIndex].srcUrl},
               {srcUrl: this.items[this.curIndex + 1].srcUrl},
            ] 
        }else if(this.curIndex == (this.items.length - 1)){ //当前图片为最后一张时候,返回的数组
             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},
              ] 
         }
     }
  },
}
image.png

为什么是三张图?

因为swiper,有两个属性,当滑动到第一张的时候isBeginning为true,这可以当做用户向左滑的判断,当滑动到最后一张的时候isEnd为true,同理可以当做用户向右滑动的判断。

[
{srcUrl: this.items[this.curIndex - 1].srcUrl},//当前图片前一张
{srcUrl: this.items[this.curIndex].srcUrl},//当前图片
{srcUrl: this.items[this.curIndex + 1].srcUrl},//当前图片后一张
] 

然后使当前索引的图片永远在数组swiperPicList中间,
1、向左滑动的时候,curIndex--,向右滑动的时候 curIndex++

但是对于swiper中间选中项向左滑到第一张,第一张会变成选中项,用户看到的其实是数组第一张图。向右同理。

所以需要使用swiper方法this.swiper.slideTo(1,0, false),使得每次滑动之后,swiper都切换到第二个为选中项,这样用户看到是就是数组的中间项。

参考API:
mySwiper.slideTo(index, speed, runCallbacks)
Swiper切换到指定slide。
index:必选,num,指定将要切换到的slide的索引。
speed:可选,num(单位ms),切换速度
runCallbacks: 可选,boolean,设置为false时不会触发transition回调函数。

除了是第一张和最后一张的时候做特殊处理。

watch:{
   curIndex(curIndex){
       if(curIndex == 0){ 
         //当滑动到第一张图片的时候,返回的数组是两张图,
         //slideTo的index应该为0,跳转到第一张图。
         this.swiper.slideTo(0,0, false);
       }else if (this.curIndex == (this.items.length-1)){
         //当滑动到最后一张图片的时候,返回数组是三张图
         //slideTo的index应该为2,跳转到第三张图。
         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实例,要特别注意
    return {
       initialSlide :1,
       on: {
         //滑动事件
         //on事件里面的this指向swiper实例,要特别注意
         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
                   }
                } 
               //这里做的是特殊处理,
              // 因为当前图片为最后一张时候,选中的图片为第三张,
              //swiperPicList数组中也是第三张,
              //最后一张滑动的方向只有向左,所以_this.curIndex - 1
             //做这个处理是最后一张向左滑动因为返回数组的原因,不能用isBeginning来判断
               if(_this.curIndex == (_this.items.length-1)){
                     _this.curIndex = _this.curIndex - 1
                }
          },
       }
     }
   },
}

最终效果


image.png

初衷是想让swiper不需要渲染所有的图片,临时做一个小数组,每次切换,小数组都是动态的获取相邻的三张照片,可能不是最优的方法,创建数组也可以进行再封装

以上只是传达一个优化思想

swiper参考文档:https://www.swiper.com.cn/api/methods/109.html

- 第三部分:

问题:图片列表,页面上几百上千张图片,用户访问页面,要拉很长时间,还要考虑用户在页面来回滚动的情况
一、图片多,要拉很长时间

①、懒加载,这个很简单。
②、缓存,这个也很简单。

二、考虑到用户在页面上下来回滚动

③、节流防抖

节流:在频繁触发的情况下,按照一定的时间去执行。

//声明一个变量当标志位,记录当前代码是否在执行
const Throttling = (fn,intelval) => {
    let time = null;
        return function (){
            if(!time){
                time = setTimeout(() => {
                    fn.call(this,arguments)
                    time = null
                },intelval) 
            }
     }
}

防抖:在频繁触发的情况下,只有足够的空闲时间,才执行一次。

//setTimeout做缓存池
const Throttling = (fn,delay) => {
    let time;
    return function (){
        if(time) clearTimeout(time)
        time = setTimeout(() => {
           fn.call(this,arguments)
        },delay) 
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269