vue.js3: 多张图片合并(vue@3.2.37)
一,安装用到的第三方库
1,安装:
liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm i -S vuedraggable@next added 2 packages in 11s
2,查看已安装的版本:
liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm list vuedraggable@next image2pdf@0.1.0 /data/vue/pdf/image2pdf └── vuedraggable@4.1.0
说明:此第三方库仅供在操作时拖动排序使用,与图片的合并无关
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/06/02/vue-js3-duo-zhang-tu-pian-he-bing-vue-3-2-37/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
或: https://gitee.com/liuhongdi
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,js代码:
<template> <div> <div style="width: 800px;margin: auto;"> <div style="margin-top: 10px;"> 选择图片(可多选): <input type="file" ref="hiddenfile" accept="image/*" multiple @change="handleFile" class="hiddenInput" /> </div> <div style="width:400px;margin: auto;margin-top: 10px;"> <div style="width:400px;font-size:12px;">可以拖动图片改变顺序</div> <draggable :list="selFiles" item-key="id" class="list-group" ghost-class="ghost" @start="dragging = true" @end="dragging = false" > <template #item="{ element,index }"> <div class="list-group-item"> <img class="fg" :id="'fg'+element.id" :src="element.fileimg" style="width:400px;display:block;" /> <div @click="del(index)" style="width:40px;height:40px;position: absolute;top:0px;right:0px;"> <el-icon style="font-size: 20px;color:white;opacity:0.8;width:40px;height:40px;"> <Delete /> </el-icon> </div> </div> </template> </draggable> </div> <div> <el-button ref="downButtonRef" :disabled="buttonEnable === true ? false : true" type="info" plain @click="down" style="width:400px;margin-top: 10px;">合并图片并下载</el-button> </div> </div> </div> </template> <script> import {ref} from "vue" import draggable from "vuedraggable"; export default { name: "ImageMerge", components: { draggable, }, setup() { //最大高度和最大宽度 let maxWidth = 0; let maxHeight = 0; //选中的图片文件,保存在数组中 const selFiles = ref([]); //得到各图片的最大高度和最大宽度 const getImgMaxWidthHeight = () => { //let allHeight = 0; for( var i=0;i<selFiles.value.length; i++ ){ let one = selFiles.value[i]; //得到高度 let img = document.getElementById("fg"+one.id); let width = img.naturalWidth; let height = img.naturalHeight; console.log("width:"+width+";height:"+height); if (width>maxWidth) { maxWidth = width; } if (height > maxHeight) { maxHeight = height; } } console.log("maxWidth:"+maxWidth+";maxHeight:"+maxHeight); } //垂直方向合并时,得到高度: const getImgDestHeight = () => { let allHeight = 0; for( var i=0;i<selFiles.value.length; i++ ){ let one = selFiles.value[i]; //得到高度 let img = document.getElementById("fg"+one.id); let width = img.naturalWidth; let height = img.naturalHeight; let destHeightOne = (maxWidth * height) / width; allHeight = allHeight+destHeightOne; } console.log("allHeight:"+allHeight); return allHeight; } //下载pdf const down = async () => { getImgMaxWidthHeight(); //得到合并后图片的高度 let destHeight = getImgDestHeight(); console.log("destHeight:"+destHeight); //生成合并后图片 const canvas = document.createElement('canvas') canvas.width = maxWidth; canvas.height = destHeight; const context = canvas.getContext('2d'); let top = 0; //合并图片 for( var i=0;i<selFiles.value.length; i++ ) { console.log(i); let one = selFiles.value[i]; //得到当前图片的高度 let img = document.getElementById("fg"+one.id); let width = img.naturalWidth; let height = img.naturalHeight; let destHeightOne = (maxWidth * height) / width; context.drawImage(img, 0, top, maxWidth, destHeightOne); top = top+destHeightOne; } //下载图片 downJpgByCanvas(canvas); } //下载图片 const downJpgByCanvas = (canvas) => { var oA = document.createElement("a"); let time = timeFormat(); oA.download = "img_"+time+'.jpg';// 设置下载的文件名,默认是'下载' oA.href = canvas.toDataURL("image/jpeg"); document.body.appendChild(oA); oA.click(); oA.remove(); // 下载之后把创建的元素删除 } //选中图片时,把图片添加到数组 const handleFile = (e) => { let filePaths = e.target.files; //清空原有缩略图 if (filePaths.length === 0) { //未选择,则返回 return } else { //清空数组中原有图片 selFiles.value.length = 0; } //把新选中的图片加入数组 for( var i=0;i<filePaths.length; i++ ){ let file = filePaths[i]; var reader = new FileReader(); reader.readAsArrayBuffer(file); //reader. let one = { id:i, fileimg:URL.createObjectURL(file), //预览用 file:file, } selFiles.value[i] = one; } setButton(); } //设置下载button是否可用 const buttonEnable = ref(false); const setButton = () => { console.log("files length:"+selFiles.value.length); if (selFiles.value.length>0) { buttonEnable.value = true; } else { buttonEnable.value = false; } } //补0 const add0 = (m) => { return m<10?'0'+m:m } //格式化时间 const timeFormat = ()=>{ var time = new Date(); var y = time.getFullYear(); var m = time.getMonth()+1; var d = time.getDate(); var h = time.getHours(); var mm = time.getMinutes(); var s = time.getSeconds(); let res = y+add0(m)+add0(d)+add0(h)+add0(mm)+add0(s); return res; } return { down, handleFile, selFiles, buttonEnable, } } } </script> <style scoped> </style>
三,测试效果:
界面:
合并后的图片:
四,查看vue框架的版本:
liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm list vue image2pdf@0.1.0 /data/vue/pdf/image2pdf ├─┬ @vue/cli-plugin-babel@5.0.8 │ └─┬ @vue/babel-preset-app@5.0.8 │ ├─┬ @vue/babel-preset-jsx@1.3.0 │ │ └── vue@3.2.37 deduped invalid: "2.x" from node_modules/@vue/babel-preset-jsx │ └── vue@3.2.37 deduped └─┬ vue@3.2.37 └─┬ @vue/server-renderer@3.2.37 └── vue@3.2.37 deduped