项目场景:
最近毕设用Vue做一个电子商城,在做商品评价的时候,我想要对某一个订单的多个商品在同一页面分别进行评价(有点类似于美团优选的商品评价),但是图片上传出现了一点问题,随手记录一下。
问题描述
通过element的upload上传图片,我想要在el-upload的成功回调传参,将上传成功的图片地址添加到图片数组里面,结果循环数组每一项的图片数组都添加上传成功的图片地址
HTML代码:
<div v-for="(item, i) in goods" :key="i">
<el-upload
:action="uploadUrl"
:headers="getAuthHeaders()"
list-type="picture-card"
:on-remove="handleRemove(item, res)"
:on-success="handleAvatarSuccess(item, res)"
>
<i class="el-icon-camera"></i>
</el-upload>
</div>
js代码
data() {
return {
goods:[],
model:{
score:null,
content:'',
contentImg:[],
}
}
},
methods:{
handleRemove(item, res) {
this.goods.forEach((v) => {
if (v.goodsId == item.goodsId) {
v.contentImg.forEach((n, i) => {
if (n == res.response.url) {
v.contentImg.splice(i, 1);
}
});
}
});
},
handleAvatarSuccess(item, res) {
//想通过每一项的商品Id来识别每一项的储存位置,从而添加图片
this.goods.forEach(v => {
if(v.goodsId == item.goodsId){
v.contentImg.push(res.url);
}
})
},
fetch() {
const res = await this.$http.get('获取订单的接口');
this.goods = (res.data?.goods || []).map(v= > {
//想在这里给数组的每一项都添加 this.model 里面的属性
return {...v, ...this.model}
})
}
}
原因分析与解决方案:
主要有三个问题:
问题一:
使用el-upload想要传参的方式错误,直接传参会覆盖掉on-success原来的参数,on-success无法自定义传参。
解决:
通过查资料:
1)可以通过 :on-success=“res => handleAvatarSuccess(item,res)” 的方式来进行传参。
2)可以通过:on-success=“handleAvatarSuccess.bind(null, {‘index’:i, ‘data’:item})” 的方式创建函数的副本调用,通常用在解决循环中使用el-upload的问题
bind的语法:
fun.bind(thisArg[, arg1[, arg2[, ...]]]) thisArg
- 当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用 new 操作符调用绑定函数时,该参数无效。
- arg1, arg2, … (可选)当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数。
问题二:
由于我想让通过请求获取的数组 goods 每一项都添加有 data 中 model 对象中的属性,而使用 { …v, …this.model } 拷贝给 goods 数组每一项的属性都是共享同一块内存的,这是属于浅拷贝,只拷贝了对象的指针,而不是对象本身,新旧对象还是共享同一块内存。需要通过深拷贝创造一个一模一样的对象,新对象和原来的对象不共享同一块内存,修改新对象的时候不会改到原来的对象。
解决:
通过 JSON.parse(JSON.stringify( this.model )) 对 model 进行深拷贝
最后上解决后的代码:
HTML代码:
<div v-for="(item, i) in goods" :key="i">
<el-upload
:action="uploadUrl"
:headers="getAuthHeaders()"
list-type="picture-card"
:on-remove="handleRemove.bind(null, {'index': i})"
:on-success="handleAvatarSuccess.bind(null, {'index': i})"
>
<i class="el-icon-camera"></i>
</el-upload>
</div>
js代码
data() {
return {
goods:[],
model:{
score:null,
content:'',
contentImg:[],
}
}
},
methods:{
handleRemove(obj, res) {
this.goods[obj.index].contentImg.forEach((v, i) => {
if (v == res.response.url) {
this.goods[obj.index].contentImg.splice(i,1);
}
})
},
handleAvatarSuccess(obj, res) {
this.goods[obj.index].contentImg.push(res.url);
},
fetch() {
const res = await this.$http.get('获取订单的接口');
this.goods = (res.data?.goods || []).map(v= > {
let model = JSON.parse(JSON.stringify(this.model))
return {...v, ...model}
})
}
}
上图:
参考文章:
ELEMENTUI中EL-UPLOAD上传图片组件上传成功函数传自定义参数
vue element-ui v-for循环el-upload上传图片 动态添加、删除
理解 javascript 里的 bind() 函数
关于深拷贝,解决过程有试过用Object.assign(),但是不成功,原因详情看:vue 项目开发中的对象拷贝