美文网首页
【小技巧】基于vue+swiper实现图片库列表点击查看大图,可

【小技巧】基于vue+swiper实现图片库列表点击查看大图,可

作者: 昏黄的乌鸦 | 来源:发表于2019-01-17 18:40 被阅读0次

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

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

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

    - 第一部分:

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

    解决办法:事件委托。

    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) 
        }
    }
    

    相关文章

      网友评论

          本文标题:【小技巧】基于vue+swiper实现图片库列表点击查看大图,可

          本文链接:https://www.haomeiwen.com/subject/cwwidqtx.html