也许今天比较无聊,突然想前端怎么把图片缓存的本地?如果是数据流,直接保存到
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.urlimage.onload = () => {canvas.width = image.widthcanvas.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])// 清空canvascanvas = 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);