资讯专栏INFORMATION COLUMN

「前端早读君001」基于ES6的Promise封装的图片资源加载通用函数(适用于vue)

cyrils / 2180人阅读

摘要:又譬如在一个多图展示的网页,由于图片过多或图片太大,我们希望图片加载完再一次性显示,而不是东一张西一张陆续显示,这时候也需要用图片一次性加载功能。

基于promise的图片资源一次性加载或者预加载

作者:NEXT卓

场景描述

不是每个网页端的用户都能用得起光纤,不是每张图片都是压缩得很小,有时候我们也想要看高清大图,但是受限于网速有时候场景是这样的:(很明显左边的第一张图片还没出来,其他的就出来了)

图片资源预加载是一个很常见的需求,在网页开发中,

譬如我们在开发一个基于canvas的游戏,涉及到图片资源的时候,为了游戏的体验,我们希望图片资源全部加载才开始游戏。

又譬如在一个多图展示的网页,由于图片过多或图片太大,我们希望图片加载完再一次性显示,而不是东一张西一张陆续显示,这时候也需要用图片一次性加载功能。

图片资源加载的原理

在浏览器向服务器发送请求的过程中,如果图片资源已经加载过一次了,则不会再从服务器加载同一个图片,
利用这个原理,我们的实现思路如下:

// 创建一个图片对象
let img = new Image()
img.src = "图片地址"
// 资源图片加载完毕
img.onload = function() {}

基于这个原理我封装了一个图片资源加载的函数,其结构如下

/**
 * @description 图片资源加载函数
 * 适用于canvas加载图片,返回的是一个promise异步对象,response 的值为一个资源对象
 * @param {Object} config 参数设置,是一个对象
 * config.sourceData - 资源对象 {key: value}   资源名:资源地址
 * config.mode - 默认为false, 即使有失败也会返回, mode为true,开启严格模式,一个失败则全部不返回
 * config.target - 要预加载的目标节点对象
 * config.response - 默认false, 是否返回promise异步对象,true为返回
 * @return {null || Promise}
 */
const loadImg = (config) => {
    // 初始化设置参数
    let sourceData = config.sourceData
    let mode = config.mode || false
    let target = config.target || []
    let needRes = config.response || false
    // 创建promise对象
    let promise = new Promise((resolve, reject) => {
        // 函数内部
        // 完整代码在最底层
     })
 }

下面让我们先来看看这个函数的威力吧!

图片加载函数描述与使用展示

函数loadImg()用于图片加载(函数实现代码在最下面),接受的参数为一个设置对象config, 该对象有4个参数键值

config.sourceData: 必选参数,资源对象 {key: value} 资源名:资源地址

config.target:可选参数,要实现加载的目标节点集

config.response:可选参数,默认false,不返回异步对象;设置为true,则返回,可通过then()进行下一步数据操作

config.mode: 可选参数,是否开启严格模式

值为false(默认值): 不开启严格模式,该模式下如果有部分图片加载失败,其余图片仍然显示

值为true: 开启严格模式,该模式下如果有部分图片加载失败,所有图片都不显示,如果需要返回结果,则返回结果是抛出一个错误

基本调用方式如下

// 图片资源对象, 对象的key值是自定义的
// 到时候如果有返回,返回的response对象的key值跟这个一样
let data = {
    img1: "http://plaechold.it/200x200",
    img2: "http://plaechold.it/200x200",
    img3: "http://plaechold.it/200x200"
}
// 需要预加载的节点集合
let images = document.querySelectorAll("img")
// 开启资源加载
loadImg({
    sourceData: data,  // 图片资源对象
    target: images,  // 预加载目标
    mode: true,  // 是否开启严格模式
    response: false  // 是否返回异步对象
})

应用实例

canvas中加载全部图片再绘制到canvas面板中

记住必须设置config.response 的值为 true 才能用then进行数据操作

let canvas = document.querySelector("canvas")
let context = canvas.getContext("2d")
// 图片资源对象
let data = {
    bird: "http://plaechold.it/200x200",  // 一只鸟的图片
    person: "http://plaechold.it/200x200",  // 一个人类的图片
    tiger: "http://plaechold.it/200x200"  // 一只老虎的图片
}
// 资源加载
loadImg({
    sourceData: data,  // 图片资源对象
    mode: true,  // 是否开启严格模式
    response: true  // 返回异步对象,然后可以使用then获取结果进行下一步处理
})
.then(res => {
    // res 也是一个对象{ bird: 图片对象, person: 图片对象, tiger: 图片对象 }
    // 获取所有的图片对象
    let images = Object.values(res)
    images.forEach((value, index) => {
        context.drawImage(value, index * 100, index * 100)
    })
})
// 记住必须设置config.response 的值为 true 才能用then进行数据操作

html页加载完毕一次性展示全部图片实例


1
2
3
// 图片资源对象
let data = {
    bird: "http://plaechold.it/200x200",  // 一只鸟的图片
    person: "http://plaechold.it/200x200",  // 一个人类的图片
    tiger: "http://plaechold.it/200x200"  // 一只老虎的图片
}
let images = document.querySelectorAll("img")
// 资源加载
loadImg({
    sourceData: data,  // 图片资源对象
    target: images,  // 要渲染的节点集
    mode: true,  // 是否开启严格模式
})

loadImg()如何在vue中优雅地实现图片加载

在vue中,由于vue是双向数据绑定,因此我们可以先这样:
假设我要加载的图片html代码如下



也就是说图片的地址是动态的,绑定着imgSrc
整个实现代码如下:


总结

基于这个函数的功能,我们可以做很多事情,除了上面的canvas绘图和展示图片外,还可以利用该
函数进行预加载,譬如当用户在浏览第一页的时候,我们可以先加载第二页的图片,具体的实现例子
这里就不多做展示了。简单的如下

 let nextImages  = document.querySelectorAll(".next-img") // 下一页的图片节点
// 用户只移动到按钮上面还没点击
button.hover = function() {
  // 预加载图片资源
  loadImg({
      sourceData: data,  // 图片资源对象
      target: nextImages,  // 要渲染的节点集
      mode: true,  // 是否开启严格模式
  })
  }
  // 这样当用户click点击以后图片资源已经在hover的时候就加载了

完整的函数实现代码如下

/**
 * @description 资源图片加载函数
 * 适用于canvas加载图片,返回的是一个promise异步对象,response 的值为一个资源对象
 * @param {Object} config 参数设置,是一个对象
 * config.sourceData - 资源对象 {key: value}   资源名:资源地址
 * config.mode - 默认为false, 即使有失败也会返回, mode为true,开启严格模式,一个失败则全部不返回
 * config.target - 要预加载的目标节点对象
 * config.response - 默认false, 是否返回promise异步对象,true为返回
 * @return {null || Promise}
 */
const loadImg = (config) => {
    // 初始化设置参数
    let sourceData = config.sourceData
    let mode = config.mode || false
    let target = config.target || []
    let needRes = config.response || false
    // 创建promise对象
    let promise = new Promise((resolve, reject) => {
        // 资源加载进度
        let loadNum = 0
        // 资源加载的结果集
        let response = {}
        // 如果是非严格模式
        if (mode === false) {
            // 遍历加载每个资源
            Object.keys(sourceData).forEach(key => {
                let source = new Image()
                // 失败或者成功都写入response
                source.onload = source.onerror = () => {
                    response[key] = source
                    loadNum++
                    if (loadNum === Object.keys(sourceData).length) {
                        // 如果有目标对象
                        if (target) {
                            target.forEach((item, index) => {
                                item.src = Object.values(sourceData)[index]
                            })
                        }
                        // 成功
                        resolve(response)
                    }
                }
               // src的赋值放在onload和onerror事件后面,这样才能兼容IE
                source.src = sourceData[key]
            })
        } else if (mode === true) {  // 严格模式:一个失败直接结束且返回空对象
            // 遍历加载每个资源
            Object.keys(sourceData).forEach(key => {
                let source = new Image()
                // 成功则写入response
                source.onload = () => {
                    response[key] = source
                    loadNum++
                    if (loadNum === Object.keys(sourceData).length) {
                        // 如果有目标对象
                        if (target) {
                            target.forEach((item, index) => {
                                item.src = Object.values(sourceData)[index]
                            })
                        }
                        resolve(response)
                    }
                }
                // 失败则返回空
                source.onerror = () => {
                    // 失败
                     reject(new Error())
                }
                // src的赋值必须放在最后,兼容IE
                source.src = sourceData[key]
            })
        }
    })
    // 结束
    if (needRes) {
        return promise
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/54496.html

相关文章

  • 前端早读001ES6Promise封装图片资源加载通用函数适用vue

    摘要:又譬如在一个多图展示的网页,由于图片过多或图片太大,我们希望图片加载完再一次性显示,而不是东一张西一张陆续显示,这时候也需要用图片一次性加载功能。 基于promise的图片资源一次性加载或者预加载 作者:NEXT卓 场景描述 不是每个网页端的用户都能用得起光纤,不是每张图片都是压缩得很小,有时候我们也想要看高清大图,但是受限于网速有时候场景是这样的:(很明显左边的第一张图片还没出来,其...

    Eric 评论0 收藏0
  • 你不知道h5

    摘要:目前,常用的模块规范主要有两种和。拦截全局请求一直接引入脚本拦截需要的回调或函数。深刻知道一个良好的命名规范的重要性,同时在项目中也会遇到一些命名的瓶颈。 基于 Three.js 的超快的 3D 开发框架:Whitestorm.js Whitestorm.js 是一款基于 Three.js 超快的 Web 应用 3D 开发框架。它为普通的 Three.js 任务提供封装、使搭建环境、...

    IntMain 评论0 收藏0
  • 前端早读003」手把手教你实现一个通用jsonp跨域方法

    摘要:什么是是的一种使用模式,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于的网页无法与不是的服务器沟通,而的元素是一个例外。利用元素的这个开放策略,网页可以得到从其他来源动态产生的资料,而这种使用模式就是所谓的。 什么是jsonp JSONP(JSON with Padding)是JSON的一种使用模式,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说...

    Taste 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<