关于图片的异步加载

515 阅读1分钟

前言

根据项目需求,要给tab加上滚动的距离,但是偶尔会出现滚动不准确的原因,后来发现是因为图片还没加载完成之后,就提前计算了滚动距离,所以这次记录一下这次的问题及解决方案。

解决方案

等待所有图片上传成功之后,才去做某些操作。img标签src资源加载成功之后,会触发onload事件,所以利用这个来看加载完之后和页面上的img标签的数量是不是相等即可。

// 等待所有图片加载完成
    waitingIamgesLoaded () {
      let parents = document.getElementsByClassName('detailall')[0]
      // 页面加载完成之后,获取页面上的img
      let imgsList = [...parents.getElementsByTagName('img')] 
      let len = imgsList.length
      // 图片加载完之后,就+1
      let imgLoadedNum = 0
     // console.log('获取当前页面所有图片数量', imgsList, len)
     // 1. 页面没有图片时,直接去dosomething
      if (imgsList.length === 0) {
        this.getModuleOffsetTop()
        console.log('页面没有图片,获取各个tab的滚动高度', this.moduleOffsetTop.join())
        return
      }
      for (let i = 0; i < imgsList.length; i++) {
        let e = imgsList[i]
        /* 
        e.complete && e.naturalHeight != 0,这句是判断是否从缓存获取的图片资源
        */
        let isLoaded = e.complete && e.naturalHeight != 0
        console.log(`查看第${i + 1}张图片状态`, isLoaded)
        // 2. 图片从缓存中获取
        if (isLoaded) {
          imgLoadedNum++;
          // 全部图片被缓存
          if (imgLoadedNum === len) {
            this.getModuleOffsetTop()
            console.log('图片被缓存下来,获取各个tab的滚动高度', this.moduleOffsetTop.join())
            return
          }
        } else {
        // 3. 图片从服务器获取
          console.log('正在加载')
          e.onload = () => {
          // 全部从服务器获取
            imgLoadedNum++;
            console.log(`第${i + 1}张加载完成,${imgLoadedNum}`) 
            if (imgLoadedNum === len) {
              this.getModuleOffsetTop()
              console.log('图片从服务器上获取,获取各个tab的滚动高度', this.moduleOffsetTop.join())
              return
            }
          }
        }
      }
    },
    // 获取各个模块的offsetTop,用来滚动
    getModuleOffsetTop () {
      console.log('获取滚动高度')
      const modules = ['content', 'aboutUs', 'process']
      this.moduleOffsetTop = modules.map((e) => {
        // console.log('document.querySelector(`#${e}`).offsetTop', document.querySelector(`#${e}`).offsetTop)
        return document.querySelector(`#${e}`).offsetTop - 80
      })
    },

注意: 经过测试,发现有以下需要注意的地方:

  1. waitingIamgesLoaded方法调用的时机,一定是DOM渲染完之后才调用的,一般可以使用异步调用这个waitingIamgesLoaded方法。

  2. 加载图片的方式,不是仅一种情况(从服务器获取资源),还有:

    • 全部缓存读取
    • 全部从服务器读取
    • 部分从缓存读取,部分从服务器读取
    • 部分图片从服务器读取资源失败,如果不监听img的error加载错误事件的话,上面写的imgLoadedNum === len条件永远不会执行!

    所以,在waitingIamgesLoade方法里面,把前三种情况考虑进去。第4种情况,可以监听img图片加载错误时,拿一张默认图片进行替换。代码如下:

    < img :src="projectImg"
          @error="handleError($event)" />
    
    handleError (e) {
      e.target.src = require('@/assets/image/default.png')
    },
    

最后

根据以上的方法,可以完美解决了滚动距离不准确的问题。后面可以优化成一个公共方法或者组件,下次再补充一下。