摘要:又譬如在一个多图展示的网页,由于图片过多或图片太大,我们希望图片加载完再一次性显示,而不是东一张西一张陆续显示,这时候也需要用图片一次性加载功能。
基于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页加载完毕一次性展示全部图片实例
// 图片资源对象 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
摘要:又譬如在一个多图展示的网页,由于图片过多或图片太大,我们希望图片加载完再一次性显示,而不是东一张西一张陆续显示,这时候也需要用图片一次性加载功能。 基于promise的图片资源一次性加载或者预加载 作者:NEXT卓 场景描述 不是每个网页端的用户都能用得起光纤,不是每张图片都是压缩得很小,有时候我们也想要看高清大图,但是受限于网速有时候场景是这样的:(很明显左边的第一张图片还没出来,其...
摘要:什么是是的一种使用模式,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于的网页无法与不是的服务器沟通,而的元素是一个例外。利用元素的这个开放策略,网页可以得到从其他来源动态产生的资料,而这种使用模式就是所谓的。 什么是jsonp JSONP(JSON with Padding)是JSON的一种使用模式,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说...
阅读 3442·2021-11-22 12:00
阅读 629·2019-08-29 13:24
阅读 2893·2019-08-29 11:31
阅读 2567·2019-08-26 14:00
阅读 3175·2019-08-26 11:42
阅读 2462·2019-08-23 18:31
阅读 783·2019-08-23 18:27
阅读 2759·2019-08-23 16:58