vue与uni-app实现“简单”的图片懒加载

973 阅读3分钟

图片懒加载,当页面可视区域出现图片元素的时候才加载对应的图片资源(其实就是把src真实的值赋值给他)

VUE

vue这里使用的是自定义指令的方式去实现图片懒加载。

    // 这里需要注意 key不要绑定 index, 绑定 id 或者随机数, 不然新增删除图片操作后,图片会出现重复的情况
    <img
      v-for="(item,index) in arrSrc"
      :key="id"
      :src="moren"
      v-lazy="item"
      alt="x"
    />
  Vue.directive("lazy", {
        inserted(el, binding) {
          //定义一个观察器,entries为状态改变元素的数组
          let observer = new IntersectionObserver((entries) => {
            // 遍历
            for (let i of entries) {
              // 如果改元素处于可视区
              if (i.isIntersecting > 0) {
                // 获取该元素
                let img = i.target;
                // 重新设置src值
                img.src = binding.value;
                //取消对该元素的观察
                observer.unobserve(img);
              }
            }
          });
          // 为 img 标签添加一个观察
          observer.observe(el);
        },
      });

上面代码来源于下面的文章,只修改了key值部分

自定义指令文章:blog.csdn.net/luo18312513…

UNI-APP

这里实现的功能是,判断元素是否出现在可视区域内,然后将src赋值替换,所以效果会比较突兀。

正常情况是需要等图片文件加载好了再去替换对应的src的,但是我这里用的是css里面的background-image: url('') 的形式去加载的图片文件,直接用img标签会出现跨域问题,而css内判断不了图片是否加载好了(暂时没发现)。

// 屏幕可视区域变量
windowTemp: {
    viewWidth: 0,
    viewHeight: 0,
},

// 没有缩略图的情况下,把thumbnailSrc当成src就行
newsList: [{
    tips: '',
    files: [{ 
        src: item.src, // 原图的路径
        thumbnailSrcShow: bgImgLoadingGif, // 加载中的图片路径 
        name: item.name, // 文件名字
        changSrcBoolean: false, // 用于判断是否替换了thumbnailSrcShow
        thumbnailSrc: item.thumbnailSrc || item.src // 预防无缩略图thumbnailSrc
    }]
}, {
    tips: '',
    files: []
}]

其实最主要的就是根据所有元素的位置获取范围内的元素有那些,结合自己的数据去进行src的修改

methods: {
    // 获取所有元素位置
    getElePosition () {
        this.$nextTick(() => {
            let query = uni.createSelectorQuery();
            let imgEle, imgboxEle
            // 使用这个方法去获取对应所有元素在页面相对于顶部的位置
            query.selectAll('.img-box').boundingClientRect(data => {
                    imgEle = data
            }).exec();

            let viewHeightTemp = this.windowTemp.viewHeight
            // 现在只能获取到位置数据,获取不到dom数据
            // for循环对应的数据,判断是否再屏幕内,再将对应的src赋值过去
            // 这里去循环对应范围内的图片数据进行替换
            let viewImgEleLength = imgEle.filter(e => e.top < viewHeightTemp).length

            let numTemp = 0
            // 循环修改,使用for循环是为了能直接
            for (let i = 0; i < this.newsList.length; i++) {
                let listE = this.newsList[i]
                for (let j = 0; j < listE.rhImgs.length; j++) {
                    let fileE = listE.rhImgs[j]
                    if (numTemp < viewImgEleLength) {
                        if (!fileE.changSrcBoolean) {
                            fileE.changSrcBoolean = true
                            fileE.thumbnailSrcShow = fileE.thumbnailSrc
                        }
                        numTemp++;
                    } else {
                        break;
                    }
                }
            }
        })
    },
    // 获取屏幕可视区域宽高的方法 
    getWindowViewSize () {
        // 获取手机宽高
        let self = this;
        uni.getSystemInfo({ 
            success(res) {
                // screenHeight 屏幕高度  注意这里获得的高度宽度都是px 需要转换rpx
                // windowWidth  可使用窗口宽度
                // windowHeight 可使用窗口高度
                // screenWidth  屏幕宽度
                self.windowTemp.viewHeight = (res.screenHeight * (750 / res.windowWidth)) / 2//窗口高度,将px 转换rpx
                self.windowTemp.viewWidth = res.windowWidth
                // self.windowTemp.viewHeight = res.windowHeight
            }
        })
    },
  }

以上就是全部内容,有优化的地方就是用户滑动屏幕很快的话,还是会和之前一样,所以需要判断当前在界面内的数据有那些(然后进行加载,我这边有缩略图的操作,所以影响不大),因此,这个只是个简单版本的懒加载。

每次写完总感觉文章很垃圾,然而我写了这么多了,哈哈,不理了,冲冲冲。