今天在用eventBus实现任意两个组件间的通信时,踩了一个坑,需求很简单,就是把左侧组件A输入的对象值this.ruleForm在点击提交按钮之后,把提交的对象插入到右侧组件B的表格数据tableData中,每提交一次就插一条数据。但是一开始按照我的理解写出来的代码运行之后出现了一个很奇怪的现象,每次点击提交按钮,后面提交的数据都会改变之前已经提交的数据,比如说第一次提交了数据a1,表格新增了一条a1的数据,第二次提交数据a2时,表格除了新增一条a2的数据,还会把a1的那条数据变得和a2一模一样,即提交N次,最终表格就新增N条一模一样的数据(以最后一次提交的数据为准)。
最终通过控制台打印push到tableData数组的对象,发现是跟vue数据里的__ob__: Observer有关,有这个属性的数据就像带着指针一样,每次一改动就会让之前跟它有关联的数据全部都被改动。
在组件A传值this.ruleForm过来之后,组件B从组件A拿到的数据target是带有__ob__: Observer的,如果直接把拿到的target push到tableData数组里面,就会出现上述的怪现象,正确操作是在push到tableData数组之前先要处理一下,让push到tableData数组的数据是不带Observer的,处理方法有两个,一个是比较笨的办法,定义一个新的对象,不直接把target赋值给它,而是把target的属性一个个的赋值给新对象,这样新对象就不会带有__ob__: Observer;另一个好一点的办法是使用Object.assign函数,即let obj2 = Object.assign({}, obj1);推荐使用这种方法,要不然万一target属性很多,一个属性一个属性的赋值,代码看上去太不简洁了。
最终解决了bug的正确代码如下:
父组件代码:
<template>
<div class="eventBus">
<el-container>
<el-aside>
<one-component></one-component>
</el-aside>
<el-main>
<two-component></two-component>
</el-main>
</el-container>
</div>
</template>
<script>
import oneComponent from './components/comA.vue'
import twoComponent from './components/comB.vue'
export default {
components:{
oneComponent,
twoComponent
},
data(){
return {
}
}
}
</script>
<style scoped>
.eventBus{
margin-top: 200px;
}
.el-container .el-aside{
margin: 20px 0 20px 20px;
}
</style>
子组件A代码:
<template>
<div class="comA">
<el-form :model="ruleForm" status-icon ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="姓名" prop="name">
<el-input v-model="ruleForm.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="ruleForm.address"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import Bus from '@/api/eventBus.js';
export default {
data(){
return {
ruleForm: {
name: '',
address: ''
},
formData:{}
}
},
methods:{
submitForm() {
console.log(this.ruleForm)
Bus.$emit('passFormData', this.ruleForm);
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
<style>
</style>
子组件B代码:
<template>
<div class="comB">
<el-table
:data="tableData"
style="width: 100%">
<!-- <el-table-column
prop="date"
label="日期"
width="180">
</el-table-column> -->
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
</div>
</template>
<script>
import Bus from '@/api/eventBus.js';
export default {
data() {
return {
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}]
}
},
mounted(){
Bus.$on('passFormData', target => {
console.log(target); // => 打印出来的是comA里面的this.ruleForm,这里的target就是comA里面的this.ruleForm
// 让obj去掉target带的__ob__: Observer,方法一(比较笨)如下:
// let obj = {};
// obj.name = target.name;
// obj.address = target.address;
// 让obj去掉target带的__ob__: Observer,方法二(比较好的方法)如下:
let obj = Object.assign({}, target);
console.log(obj);
this.tableData.push(obj);
// console.log(this.tableData)
});
}
}
</script>
<style>
</style>
eventBus.js代码:
import Vue from 'vue';
export default new Vue();
解决问题参考的博客如下:
vue2 如何去除带__ob__这样的数据?添加链接描述