0.结论
先放结论:vue中给对象添加属性时,不要直接赋值(如对空对象targetBrand使用this.targetBrand.brandLogo = picUrl赋值),应使用$set(如this.$set(this.targetBrand,'brandLogo',picUrl))。
前者添加的属性是非响应式的,因此其值的更新不会引发vue的状态变化,而后者添加的属性则是响应式的。有关响应式的更多内容可以查看深入响应式原理 — Vue.js
1.背景
前端开发,技术栈Vue+Element Ui
问题是这样的,我有一个自定义组件QiniuUpload,大概是这样的
简洁起见无关代码就不展示了,上面还有一个根据picUrl属性展示对应地址图片的标签。重点关注红框中的内容,从上到下分别是:
- picUrl:props中的图片地址,负责由父组件动态传值,从而在子组件展示
- picUrlData:data中的图片地址,负责接收上传回调的图片地址,同时通过watch picUrl与其同步
- 将子组件上传回调的地址发送给父组件,以便父组件保存到数据库

2.问题
我在父组件的一个新增/修改共用的el-dialog中用到了该组件,用来给数据库条目添加图片logo。修改现有条目时一切都运行正常,问题出在新增时。
新增时,我发现我通过子组件上传的图片地址尽管成功通过$emit回调给了父组件,父组件也成功更新了自己targetBrand.brandLogo的值,但父组件动态绑定给子组件的:pic-url="targetBrand.brandLogo"并没有传达给子组件的props,props中存储的仍然是之前的地址。
只有我修改dialog中其他元素时,新的图片地址才会同步到子组件props。
3.解决方法
最终我发现,这是由于我在新增时将父组件存储表单元素的data类targetBrand设置为了空对象,随后使用 this.targetBrand.brandLogo = picUrl 给图片地址赋值,这就导致新增的图片地址属性是非响应式的,无法被vue监听到变化(见下图)
因此只需要在父组件接收子组件$emit上传地址的回调函数中,使用 this.$set(this.targetBrand,'brandLogo',picUrl) 取代之前的赋值方式即可解决。