一张图片前端代码:
<el-upload
class="upload-demo"
action="http://localhost:3000/upload" //后端api地址
:data="uploadData" //要附带的数据,这里带了用户名传到后端
:on-success="getAvatarSuccess" //成功之后的回调函数,第一个参数
//是后端返回的值
:before-upload="beforeAvatarUpload"//上传之前的预处理函数
list-type="picture"//缩略图
>
<el-button size="small" type="primary">点击上传头像</el-button>
script部分:
data(){
return{
avatar:'',
uploadData:{
name:""
},
}
}
},
methods:{
beforeAvatarUpload(file){
const isLt=file.size/1024/1024/<4;
const isJPG=file.type=='image/jepg';
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!')
}
if (!isLt) {
this.$message.error('上传头像图片大小不能超过 4MB!')
}
return isLt&&usJPG;//以此让组件判断是否发起请求
}
getAvatarSuccess(res){
this.avatar=res.avatar
//注意,若想给img动态绑定src,必须用require($baseIMGurl+this.avatar);
}
}
后端部分:
要用到formidable中间件,即cnpm install formidable;
原理分析:
form.parse会解析从前端传来的req里的表单数据,把username等放在fields中,把图片文件等放在files中,可以自己打印一下看看,主要过程是得到图片->修改名字->保存->发送图片新名字到前端(是新名字,不包括基本路径,基本路径在前端设置好,这样利于在数据库保存图片的路径)
app.post('/upload', (req, res) => {
let form = new formidable.IncomingForm()
form.encoding = 'utf-8' // 编码
form.keepExtensions = true // 保留扩展名
form.uploadDir ='src/assets/images/' //文件存储路径 最后要注意加 '/' 否则会被存在public下
;
form.parse(req, (err, fileds ,files) => { // 解析 formData 数据
if(err) return next(err)
let username = fileds.name //用户名 用于修改用户头像路径
let oldPath = files.file.path //获取文件路径 ~/public/images/<随机生成的文件名>.<扩展名>
let imgname = files.file.name //前台上传时的文件名 也就是文件原本的名字
let userImgname = imgname.replace(/[^.]+/, username) //把扩展名前的文件名给替换掉
//我这里为了方便存储 统一将文件名改为 <用户名>.jpg
let newPath = path.join(path.dirname(oldPath), userImgname) ;
fs.rename(oldPath, newPath, (err) => {//fs重命名
if(err) return next(err)
res.json({ avatar: userImgname }) ;
})
})
})
下面是多张图片教程:
前端代码:
原理分析:先取消upload组件自动上传,指定http-request(上传规则)函数
,利用FormData对象的append属性,往formdata中添加图片数据,传到后端;
在按下确定按钮后,this.$refs.upload.submit()触发,这之后的append才会生效
接着往formdata中append图片数据即可
<el-upload
class="upload-demo"
multiple
action="http://localhost:3000/uploads"
list-type="picture-card"
:auto-upload="false"
:http-request="uploadFile"
ref="upload"
>
<i class="el-icon-plus"></i>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且单个不超过4M</div>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click=" dnc_cancle">取 消</el-button>
<el-button type="primary" @click="dnc_confirm">确 定</el-button>
</span>
前端script部分:
uploadFile(file){
this.imgsArr.push(file.file);//往一个数组中添加图片数据
},
dnc_confirm方法:
this.$refs.upload.submit();
var index=1;//用来给图片命名
this.textarea='';
this.imgsArr.forEach((img,index)=>{
this.formDate.append(`img${index++}`,img);//这里用到index++,防止前面添加的图片被后面的覆盖,下面后端代码有讲如何循环这个数组
})
this.formDate.append('username',this.uploadData.name);
this.formDate.append('info',this.info);
let config = {
headers: {
'Content-Type': 'multipart/form-data'
}
}//设置请求头!
this.$axios.post('http://localhost:3000/uploads',this.formDate,config).then(inf=>{
this.info="";
this.$message.success('添加成功');
this.dialogVisible=false;
this.reload();
})
后端代码:
const form=new formidable.IncomingForm();
form.uploadDir='src/assets/d-image/';
form.keepExtensions=true;
form.encoding='utf-8';
const imgArr=[];
form.parse(req,(err,fields,files)=>{
if(err)console.log(err);
for(var key in files){//循环files对象
const file=files[key];
const oldPath=file.path;
const oldName=file.name;
const newName=oldName.replace(/[^.]+/,Math.random()+parseInt(new Date().getTime()));//以时间戳命名+random,防止图片重名
const newPath=path.join(path.dirname(oldPath),newName);
fs.rename(oldPath,newPath,(err)=>{
if(err) return next(err);
imgArr.push(newName);//把图片新名字压进数组
});
res.json({state:1,imgs:imgArr});