图片上传例子-前后端
说我的文章质量不高?开什么玩笑!
高得很呢!!
图片上传,并不简单
会后台的,不知道前端怎么上传图片
会前端的,不知道后台怎么保存图片
这个文章,一次性把前后端都展示了
用java PHP nodejs python后端语言,道理都一样的
前后端源码地址
源码1:vue+node:https://gitee.com/618859/vue-node-simple-uploadimg
源码2:https://gitee.com/618859/picture-upload-node
效果
效果1:vue
效果2:html
安装依赖
1.安装node环境:去node官网下载node安装即可
2.安装依赖 npm i
3.运行 node server.js
4.去浏览器访问 http://localhost:7070/
前端核心代码
其实全部完整代码在文章开头,自己去下载,不懂下载的同学,私信我
我微信号 yizheng369 不懂可以问我
前端代码:
<template>
<div class="hello">
<h1 style="text-align: left">图片列表
<el-button type="primary" @click="addActive"
>添加活动</el-button
>
</h1>
<hr />
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="活动名称" width="180">
</el-table-column>
<el-table-column label="海报" width="100">
<template slot-scope="scope">
<div class="poster img100">
<img :src="scope.row.poster"/>
</div>
</template>
</el-table-column>
<el-table-column prop="desc" label="简介"> </el-table-column>
<el-table-column label="操作" width="220">
<template slot-scope="scope">
<el-button type="success" @click="readFun(scope.row)">查看</el-button>
<el-button type="primary" @click="editFun(scope.row)">编辑</el-button>
<el-button type="danger" @click="delFun(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
:title="dialogType == 1 ? '新增' : (dialogType == 2 ? '查看' : '修改')"
:visible.sync="showDialog"
width="45%">
<el-form ref="form" :model="form" label-width="110px">
<el-form-item
v-for="(item,index) in activeArr"
:key="item.name+index"
:label="item.name">
<el-input
v-if="item.inputType === 'text'"
:disabled="dialogType == 2"
v-model="item.value">
</el-input>
<div v-else-if="item.inputType === 'image'" class="demo-block">
<el-upload
class="avatar-uploader"
action="#"
:disabled="dialogType == 2"
:show-file-list="false"
:auto-upload="isAutoUpload"
:on-change="onChange"
:before-upload="beforeAvatarUpload">
<img v-if="item.value" :src="item.value" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
<el-input
v-else-if="item.inputType === 'textarea'"
:disabled="dialogType == 2"
type="textarea"
:autosize="{ minRows: 4, maxRows: 4}"
v-model="item.value">
</el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="showDialog = false">取 消</el-button>
<el-button type="primary" @click="sureFun">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
dialogType: 1,
showDialog: false,
isAutoUpload: false,
form: {
name: "",
desc: ""
},
tableData: [
{
name: "2016-05-02",
desc: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
},
{
name: "2016-05-04",
desc: "王小虎",
address: "上海市普陀区金沙江路 1517 弄",
},
],
baseActiveArr: [
{
name: '活动主题',
enName: 'name',
inputType: 'text',
valueType: 'text',
value: '活动主题1'
},
{
name: '备注',
enName: 'desc',
inputType: 'textarea',
valueType: 'textarea',
value: '备注1'
},
{
name: '活动海报',
enName: 'poster',
inputType: 'image',
valueType: 'file',
value: ''
}
],
activeArr: [],
activeTopImg: '',
currentPoster: ''
};
},
created() {
this.getData();
},
methods: {
// 深拷贝对象
copyObj(obj){
return JSON.parse(JSON.stringify(obj))
},
answerFun(str="确定删除吗?"){
return new Promise((resolve,reject)=>{
this.$confirm(str, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
resolve(true)
}).catch(() => {
resolve(false)
});
})
},
formatterStart(row) {
return this.formatterTime(row.startTime);
},
formatterEnd(row) {
return this.formatterTime(row.endTime);
},
formatterTime(time) {
let date = new Date(time);
let month = date.getMonth() + 1;
month = this.addZero(month);
let day = date.getDate();
day = this.addZero(day);
let h = date.getHours();
h = this.addZero(h);
let m = date.getMinutes();
m = this.addZero(m);
let s = date.getSeconds();
s = this.addZero(s);
return `${date.getFullYear()}-${month}-${day} ${h}:${m}:${s}`;
},
addZero(one) {
if (one < 10) {
one = "0" + one;
}
return one;
},
onChange(file, fileList) {
console.log("file", file);
this.activeArr[2].value = URL.createObjectURL(file.raw);
this.activeTopImg = file.raw;
},
beforeAvatarUpload(file) {
const isJPG = file.type === "image/jpeg";
const isLt2M = file.size / 1024 / 1024 < 15;
if (!isJPG) {
this.$message.error("上传头像图片只能是 JPG 格式!");
}
if (!isLt2M) {
this.$message.error("上传头像图片大小不能超过 15MB!");
}
return isJPG && isLt2M;
},
// 新增1
addActive() {
this.dialogType = 1;
this.showDialog = true;
this.activeArr = this.copyObj(this.baseActiveArr);
},
dealRowData(row) {
// 赋值
let arr = this.copyObj(this.baseActiveArr);
for (let i = 0; i < arr.length; i++) {
if (arr[i].enName == "activeTime") {
arr[i].startTime = row["startTime"];
arr[i].endTime = row["endTime"];
} else {
let val = row[arr[i].enName];
if (!isNaN(val)) {
val = val / 1;
}
arr[i].value = val;
}
}
return arr;
},
// 查看2
readFun(row) {
this.dialogType = 2;
this.showDialog = true;
this.activeArr = this.dealRowData(row);
console.log("readFun-row", row);
},
// 编辑3
editFun(row) {
this.id = row.id;
this.dialogType = 3;
this.showDialog = true;
this.currentPoster = row.poster;
this.activeArr = this.dealRowData(row);
console.log("editFun-row",this.activeArr, row);
},
// 删除
async delFun(row) {
console.log("delFun-row", row);
let rel = await this.answerFun();
let { id, poster } = row;
if (poster) {
let index = poster.lastIndexOf("/");
poster = poster.slice(index + 1);
}
if (rel) {
// 执行删除
this.$axios
.post(window.API + "/delActive", { id, poster })
.then((res) => {
console.log("删除-返回:", res);
if (res.data.error == 0) {
this.$message({
message: "操作成功",
type: "success",
});
// 重新获取数据
this.getData();
} else {
let msg = res.data.msg;
if (msg == "{}") {
msg = "";
}
this.$message({
message: "服务器出错" + msg,
type: "error",
});
}
})
.catch((err) => {
console.log("出错", err);
this.$message({
message: "服务器出错!",
type: "error",
});
});
}
},
getData() {
this.$axios
.get(window.API + "/getActiveList")
.then((res) => {
console.log("活动列表:", res);
// 将数据渲染到页面上
this.tableData = res.data.data;
})
.catch((err) => {
console.log("出错", err);
this.$message({
message: "服务器出错!",
type: "error",
});
});
},
sureFun() {
// 2:查看
if (this.dialogType === 2) {
this.showDialog = false;
return;
}
// 准备上传文件数据
var formData = new FormData();
// 是新增,或者更新
let isAdd = this.dialogType === 1 ? "isAdd" : "isUpdate";
formData.append("isAdd", isAdd);
// 更新
if (isAdd == "isUpdate") {
formData.append("id", this.id);
// 更新时,如果图片也更新了,那就删除旧图片
if (this.currentPoster) {
let poster = this.currentPoster;
if (poster) {
let index = poster.lastIndexOf("/");
poster = poster.slice(index + 1);
}
formData.append("poster", poster);
}
} else {
formData.append("id", Date.now()+'');
}
formData.append("file", this.activeTopImg); // 活动宣传海报图片
this.activeTopImg = ""; // 赋值完毕,清空数据
formData.append("name", this.activeArr[0].value); // 主题
formData.append("desc", this.activeArr[1].value); // 描述
// axios接收文件格式数据 https://blog.csdn.net/m0_38069630/article/details/79105709
let config = {
headers: {
"Content-Type": "multipart/form-data",
},
};
this.$axios
.post(window.API + "/fileUpload", formData, config)
.then((res) => {
console.log("提交:", res);
if (res.data.error == 0) {
this.showDialog = false;
this.$message({
message: "提交成功",
type: "success",
});
// 重新获取数据
let timer = setTimeout(()=>{
clearTimeout(timer)
this.getData();
},1500)
} else {
let msg = res.data.msg;
if (msg == "{}") {
msg = "";
}
this.$message({
message: "服务器出错" + msg,
type: "error",
});
}
})
.catch((err) => {
console.log("出错", err);
this.$message({
message: "服务器出错!",
type: "error",
});
});
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.img100 img{
width: 100%;
height: 100%;
}
/deep/ .celltd .cell{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/deep/ .el-dialog__body{
padding: 10px 20px;
}
/deep/ .el-form-item__label{
background-color: #f3f2f2;
}
/deep/ .el-form-item__content{
padding-left: 5px;
}
/deep/.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
.poster{
width: 65px;
height: 65px;
padding: 2px;
border-radius: 6px;
border: 1px solid #ddd;
overflow: hidden;
background-size: 100% 100%;
}
</style>