工做中遇到一个这么一个需求:这是一个多图上传的场景,若是用户上传选择多张图片,则上传后直接展现多张图片,若是上传的图片是gif动图,则须要分解这张动图拆分红一帧一帧的单张图片,再按顺序展现出来。javascript
这里最核心的就是2,3步,很是庆幸有https://github.com/buzzfeed/libgif-js 这个库,才得以实现后面的步骤;java
因为是公司项目就不展现界面和完整代码,只放关键代码:git
import { SuperGif } from './libgif.js'
// 判断文件格式并展现的函数 pre_upload() { // 点击上传按钮触发弹出文件选择框 const input = document.createElement('input'); input.setAttribute('type', 'file'); // 注意要设置多选属性 input.setAttribute('multiple', 'true'); input.addEventListener('change', (e) => { this.img_list = []; this.can_upload = true; this.qiniu_url_list = []; // 判断是gif格式则交给this.pre_load_gif函数处理 if (/(image\/gif)/.test(e.path[0].files[0].type)) { this.pre_load_gif(e.path[0].files[0]) return; } // 若是是上传多张静态的png、jpg图片则直接转换成baseURL var img_list = []; for(let i=0,item; item = e.path[0].files[i]; i++) { if (!/(image\/png)|(image\/jp(e?)g)/.test(item.type)) { alert('请上传jpg、png格式的图片') return; } img_list.push({ file_name: item.name, url: URL.createObjectURL(item), file: item, }) } this.img_list = img_list }); input.click(); },
dataURLtoFile(dataurl, filename) { const arr = dataurl.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); var n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, {type:mime}); }, // 将canvas转换成file对象 convertCanvasToImage(canvas, filename) { return this.dataURLtoFile(canvas.toDataURL('image/png'), filename); }, pre_load_gif(gif_source) { var img_list = []; const gifImg = document.createElement('img'); // gif库须要img标签配置下面两个属性 gifImg.setAttribute('rel:animated_src', URL.createObjectURL(gif_source)) gifImg.setAttribute('rel:auto_play', '0') // 新建gif实例 var rub = new SuperGif({ gif: gifImg } ); rub.load(() => { var img_list = []; for (let i=1; i <= rub.get_length(); i++) { // 遍历gif实例的每一帧 rub.move_to(i); // 将每一帧的canvas转换成file对象 let cur_file = this.convertCanvasToImage(rub.get_canvas(), gif_source.name.replace('.gif', '') + `-${i}`) img_list.push({ file_name: cur_file.name, url: URL.createObjectURL(cur_file), file: cur_file, }) } this.img_list = img_list }); },
至此,核心功能基本实现,上面的函数已经将gif分解成多张图片存放在this.img_list 这个数组里面。github
接下来只要拿img_list数组里的file对象上传到服务器便可。canvas
上传方式各不相同,这里就不放具体代码了,须要注意的是,图片上传是异步操做,多图上传须要得知全部的图片所有上传成功才能肯定上传完成,因此若是上传的函数返回的是promise对象,则能够直接用Promise.all
函数便可得知全部图片上传完毕的回调。数组