Open NextBoy opened 6 years ago
不是每个网页端的用户都能用得起光纤,不是每张图片都是压缩得很小,有时候我们也想要看高清大图,但是受限于网速有时候场景是这样的:(很明显左边的第一张图片还没出来,其他的就出来了)
图片资源预加载是一个很常见的需求,在网页开发中,
在浏览器向服务器发送请求的过程中,如果图片资源已经加载过一次了,则不会再从服务器加载同一个图片, 利用这个原理,我们的实现思路如下:
// 创建一个图片对象 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个参数键值
基本调用方式如下
// 图片资源对象, 对象的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 // 是否返回异步对象 })
记住必须设置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中图片的src地址请务必为空,src="" --> <img alt="1" src=""> <img alt="2" src=""> <img alt="3" src="">
// 图片资源对象 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, // 是否开启严格模式 })
在vue中,由于vue是双向数据绑定,因此我们可以先这样: 假设我要加载的图片html代码如下
<img :src = "imgSrc.img1"> <img :src = "imgSrc.img2"> <img :src = "imgSrc.img3">
也就是说图片的地址是动态的,绑定着imgSrc 整个实现代码如下:
<template> <div class="img-wrap"> <img :src = "imgSrc.img1"> <img :src = "imgSrc.img2"> <img :src = "imgSrc.img3"> </div> </template> <script > export default { data() { // 图片绑定的数据 imgSrc: { img1: '', img2: '', img3: '' }, // 要加载的图片地址 loadSrc: { img1: 'http://placehold.it/100x100', img2: 'http://placehold.it/200x200', img3: 'http://placehold.it/300x300' } }, created() { loadImg({ sourceData: this.loadSrc, response: true // 开启返回response }) .then(() => { // 将加载好的图片地址赋值给imgSrc this.imgSrc = Object.assign({}, this.loadSrc) }) } } </script>
基于这个函数的功能,我们可以做很多事情,除了上面的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({}) } // src的赋值必须放在最后,兼容IE source.src = sourceData[key] }) } }) // 结束 if (needRes) { return promise } }
基于promise的图片资源一次性加载或者预加载
场景描述
不是每个网页端的用户都能用得起光纤,不是每张图片都是压缩得很小,有时候我们也想要看高清大图,但是受限于网速有时候场景是这样的:(很明显左边的第一张图片还没出来,其他的就出来了)
图片资源预加载是一个很常见的需求,在网页开发中,
图片资源加载的原理
在浏览器向服务器发送请求的过程中,如果图片资源已经加载过一次了,则不会再从服务器加载同一个图片, 利用这个原理,我们的实现思路如下:
基于这个原理我封装了一个图片资源加载的函数,其结构如下
下面让我们先来看看这个函数的威力吧!
图片加载函数描述与使用展示
函数loadImg()用于图片加载(函数实现代码在最下面),接受的参数为一个设置对象config, 该对象有4个参数键值
基本调用方式如下
应用实例
canvas中加载全部图片再绘制到canvas面板中
记住必须设置config.response 的值为 true 才能用then进行数据操作
html页加载完毕一次性展示全部图片实例
loadImg()如何在vue中优雅地实现图片加载
在vue中,由于vue是双向数据绑定,因此我们可以先这样: 假设我要加载的图片html代码如下
也就是说图片的地址是动态的,绑定着imgSrc 整个实现代码如下:
总结
基于这个函数的功能,我们可以做很多事情,除了上面的canvas绘图和展示图片外,还可以利用该 函数进行预加载,譬如当用户在浏览第一页的时候,我们可以先加载第二页的图片,具体的实现例子 这里就不多做展示了。简单的如下
完整的函数实现代码如下