也许今天比较无聊,突然想前端怎么把图片缓存的本地?如果是数据流,直接保存到
localStorage
,但是如果是网络url地址怎么办?存个url肯定没有什么意义,苦思冥想还是把图片保存为base64
格式,这又遇到了问题,怎么才能把url转成base64
呢?于是就想到了canvas
。
以react
为例,首先接口获取数据,在取到数据后,先判断有没有缓存,如果有就取缓存中的数据,如果没有,则使用canvas
将其转化成base64
存储就可以了。为了方便操作,在localStorage
存储中添加了一个更新时间,如果想更新缓存可以改变时间就可以了,其次用url当key
值,主要是为了方便取用。
import React, { useState, useEffect } from 'react'
const CacheImg = () => {
let [imgURL, setImgURL] = useState('')
useEffect(() => {
getData()
}, [])
const getData = () => {
new Promise(resolve => {
// 这里模仿接口发送异步请求
let data = {
updateTime: '2023-11-09 12:00:00',
url: 'https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao-small.jpg'
}
resolve(data)
}).then(res => {
let localData = JSON.parse(localStorage.getItem('cacheUrls')) || {}
// 先获取本地存储的数据,当更新时间和url都一样时,就取缓存数据
if (localData.updateTime === res.updateTime && localData[res.url]) {
setImgURL(localData[res.url])
} else {
let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d')
let image = new Image()
// 解决图片跨域
image.crossOrigin = 'Anonymous'
image.src = res.url
image.onload = () => {
canvas.width = image.width
canvas.height = image.height
// 绘制图片-在左上角的位置
ctx.drawImage(image, 0, 0)
// 存个更新时间,方便更新
let cacheObj = {
updateTime: res.updateTime,
// 'https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao-small.jpg': ''
}
// 返回值是一个数据url,是base64组成的图片的源数据
cacheObj[res.url] = canvas.toDataURL('image/png')
// 本地存储
localStorage.setItem('cacheUrls', JSON.stringify(cacheObj))
setImgURL(cacheObj[res.url])
// 清空canvas
canvas = null
}
}
})
}
return <div>{imgURL ? <img src={imgURL} /> : ''}</div>
}
export default CacheImg
看一下network,只有第一次会加载图片,其他情况都会取缓存中的,大大的节约了获取图片的时间,你也许会说,浏览器本身就带缓存,可是,在开发中,有时候会开启无缓存模式,这个时候对一成不变的图片还每次都加载,岂不是浪费时间?即便关了浏览器、关了电脑再打开也不会在去请求url。
为了防止保存很多无用的图片,可以给localStorage
设置一个过期时间,虽然localStorage
本身没有提供设置有效期的方法,但我们可以自己封装个方法来实现。
例如这样:
Storage.prototype.setExpire = (key, value, expire) => {
let obj = {
data: value,
time: Date.now(),
expire: expire,
}
//localStorage 设置的值不能为对象,转为json字符串
localStorage.setItem(key, JSON.stringify(obj))
};
Storage.prototype.getExpire = (key) => {
let val = localStorage.getItem(key)
if (!val) {
return val
}
val = JSON.parse(val)
if (Date.now() - val.time > val.expire) {
localStorage.removeItem(key)
return null
}
return val.data
};
- 获取数据
let storage = localStorage.getExpire(`cacheUrls`)
- 设置数据
// 有效期七天
localStorage.setExpire(`cacheUrls`, vals, 86400000 * 7);