说在前面
这篇文章是以前写的,略微有些冗余与复杂,简约整理请看这篇文章:父组件向子组件通信与子组件向父组件通信问题总结
父组件向子组件传值
父组件向子组件传值主要是通过props来实现的(或者另一种说法:子组件通过props来接收父组件传递的值。更好理解),需要注意的是,props是单向绑定,后文将会说明这个属性。眼过千遍不如手过一遍,接下来将通过两个实例来展现props是如何实现父组件向子组件传值的
- 首先定义一个父组件,命名为TheParentComponent,并在同级目录定义一个子组件,命名为TheChildComponent。父组件代码如下
//1. 这是父组件
<template>
<div id="app">
<p>这是父组件</p>
<TheChildComponent :info="message"></TheChildComponent> <-- 使用子组件。此处的info是动态绑定,如果静态绑定,则不需要冒号(v-bind的缩写) -->
</div>
</template>
<script>
import TheChildComponent from '@/components/TheChildComponent' // 导入子组件文件
export default {
// 引用组件
components: {
//此处两种写法都可以
// 'TheChildComponent':TheChildComponent
TheChildComponent
},
data() {
return {
message: '这是父组件传来的值',
}
}
}
</script>
子组件代码如下
//1. 这是子组件
<template>
<div>
<p>*****************************</p>
<p>这是子组件</p>
<div>{{info}}</div>
<p>*****************************</p>
</div>
</template>
<script>
export default {
props:['info']
}
</script>
运行结果如下 绿框是父组件部分,红框是子组件部分,父组件中message的值“这是父组件传来的值”成功传给子组件,注意,此处是动态绑定;若为静态绑定,即<TheChildComponent :info="message"></TheChildComponent>
中的info则没有冒号,<TheChildComponent info="message"></TheChildComponent>
,这时,传递给子组件的值为message
接下来我们尝试父组件向子组件传递一个对象数组,首先,我在本地localStorage中存储了一个对象数组作为测试数据,并在生命周期函数created中读取到这些数据。具体代码如下
//1. 这是父组件
<template>
<div id="app">
<p>这是父组件</p>
<TheChildComponent :info="tableData"></TheChildComponent> <-- 动态绑定tableData -->
</div>
</template>
<script>
import TheChildComponent from '@/components/TheChildComponent'
export default {
components: {
// 'TheChildComponent':TheChildComponent
TheChildComponent
},
data() {
return {
message: '这是父组件传来的值',
tableData: ''
}
},
created() {
this.tableData = JSON.parse(localStorage.getItem('form')) // 从本地存储读取数据
}
}
</script>
子组件代码没有任何变化,运行结果如下
我们可以看到,我们已经成功实现父组件向子组件传递一个对象数组。接下来,我们美化一下页面,在子组件中设计一个表格,将这些数据填充进去。此时,我们只需要在子组件中修改代码即可,父组件代码无需改动,子组件代码如下
//1. 这是子组件
<template>
<div>
<p>*****************************</p>
<p>这是子组件</p>
<div>{{info}}</div>
<el-table
border="1px"
:data="info" //此处绑定表格数据
style="width:100%;margin-top:10px;"
>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
<el-table-column prop="sid" label="学号"></el-table-column>
<el-table-column prop="schoolarea" label="所属校区"></el-table-column>
<el-table-column prop="date" label="入学时间"></el-table-column>
<el-table-column prop="studytype" label="学制"></el-table-column>
<el-table-column prop="desc" label="其他说明"></el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete" @click.native.prevent="deleteRow(scope.$index,scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<p>*****************************</p>
</div>
</template>
<script>
export default {
props:['info']
}
</script>
运行结果如下
到这里,父组件向子组件传递对象数组就完成啦。我们可以发现,props既可以传递基本数据类型数据,如String、number等,也可以传递引用数据类型数据,如数组、对象等。
子组件向父组件传值
子组件向父组件传值是通过$emit
实现的,子组件可以通过$emit
触发父组件中的自定义事件达到传值目的。接下来我们继续以上面的实例为例,我们给这个列表添加一个修改学生信息功能,具体需求是这样的,当鼠标点击某一行时,会弹出一个已经填充好当前行数据的表单,然后修改后将新的表格数据通过$emit
传递给父组件,达到修改的功能。
首先,我们先为这个表格绑定一个监听行事件
//1. 这是子组件
<el-table
border="1px"
:data="info"
style="width:100%;margin-top:10px;"
@row-click="handleEdit"
>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
<el-table-column prop="sid" label="学号"></el-table-column>
<el-table-column prop="schoolarea" label="所属校区"></el-table-column>
<el-table-column prop="date" label="入学时间"></el-table-column>
<el-table-column prop="studytype" label="学制"></el-table-column>
<el-table-column prop="desc" label="其他说明"></el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete" @click.native.prevent="deleteRow(scope.$index,scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
此处只是添加了一行代码@row-click="handleEdit"
,这个事件是实现点击行弹出表单并填充行数据,实现如下
handleEdit(row) {
if(this.deleteRowButton == false){
this.editFormVisible=true
let formdata= JSON.parse(JSON.stringify(row))
this.editForm=formdata
}
}
后方便后面描述,先展示子组件完整代码,具体如下
<template>
<div>
<p>*****************************</p>
<p>这是子组件</p>
<div>{{info}}</div>
<el-table
border="1px"
:data="info"
style="width:100%;margin-top:10px;"
@row-click="handleEdit"
>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
<el-table-column prop="sid" label="学号"></el-table-column>
<el-table-column prop="schoolarea" label="所属校区"></el-table-column>
<el-table-column prop="date" label="入学时间"></el-table-column>
<el-table-column prop="studytype" label="学制"></el-table-column>
<el-table-column prop="desc" label="其他说明"></el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete" @click.native.prevent="deleteRow(scope.$index,scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
title="提示"
id="editDialog"
:visible.sync="editFormVisible"
width="30%"
>
<el-form :model="editForm" label-width="80px" ref="editForm">
<el-form-item label="学生姓名">
<el-input v-model="editForm.name"></el-input>
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="editForm.sex">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="学生学号">
<el-input v-model="editForm.sid" disabled></el-input>
</el-form-item>
<el-form-item label="所在校区">
<el-select v-model="editForm.schoolarea" placeholder="请选择所在校区">
<el-option label="校本部" value="校本部"></el-option>
<el-option label="渭水校区" value="渭水校区"></el-option>
<el-option label="研究生院" value="研究生院"></el-option>
</el-select>
</el-form-item>
<el-form-item label="入学时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="editForm.date" style="width: 100%;"></el-date-picker>
</el-col>
</el-form-item>
<el-form-item label="学制">
<el-radio-group v-model="editForm.studytype">
<el-radio label="四年制" name="type"></el-radio>
<el-radio label="五年制" name="type"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="其他说明">
<el-input type="textarea" v-model="editForm.desc"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click.native="editFormVisible = false">取消</el-button>
<el-button type="primary" @click="editSubmit">提交</el-button>
</div>
</el-dialog>
<p>*****************************</p>
</div>
</template>
<script>
export default {
props:['info'],
data() {
return {
deleteRowButton: false,
editFormVisible: false,//控制表单是否弹出
editForm: {
name: '',
sex: '',
sid: '',
schoolarea: '',
date: '',
studytype: '',
desc: '',
}
}
},
methods: {
handleEdit(row) {
if(this.deleteRowButton == false){
this.editFormVisible=true
let formdata= JSON.parse(JSON.stringify(row))
this.editForm=formdata
}
},
editSubmit(){
this.$confirm('确认修改该学生的信息吗?','提示',{
confirmButtonText:'确认修改',
cancelButtonText:'取消修改',
type:'warning'
}).then(() => {
let data=this.info
for(let i=0;i<data.length;i++){
if(data[i].sid==this.editForm.sid){
data[i]=this.editForm
}
}
this.$emit('updateData',data)
console.log(data)
this.editFormVisible=false
this.reflash()
// this.getStudentList()
}).then(() => {
this.$message({
type:'success',
message:'修改成功'
})
}).catch(() => {
this.$message({
type:'info',
message:'已取消'
})
})
},
reflash(){
let NewPage = "_empty" + "?time=" + new Date().getTime() / 500;
this.$router.push(NewPage);
this.$router.go(-1);
}
}
}
</script>
<style scoped>
#editDialog{
margin:0 auto;
text-align: left;
}
</style>
editSubmit()
这个方法首先将子组件通过props接受到父组件的info赋值给data,然后遍历数组修改对应的行数据,然后通过this.$emit('updateData',data)
将data传给父组件自定义的事件名updateData,然后父组件调用自定义的方法完成数据修改。父组件自定义的方法代码如下
//1. 这是父组件
<template>
<div id="app">
<p>这是父组件</p>
<TheChildComponent :info="tableData" @updateData="onUpdateData"></TheChildComponent>
</div>
</template>
<script>
import TheChildComponent from '@/components/TheChildComponent'
export default {
components: {
// 'TheChildComponent':TheChildComponent
TheChildComponent
},
data() {
return {
message: '这是父组件传来的值',
tableData: ''
}
},
created() {
this.tableData = JSON.parse(localStorage.getItem('form'))
},
methods: {
onUpdateData (data){
localStorage.setItem('form',JSON.stringify(data))
}
}
}
</script>
在父组件引用子组件中添加@updateData="onUpdateData"
,这是父组件自定义的事件方法,当子组件this.$emit('updateData',data)
后,子组件触发父组件自定义的事件updateData,父组件调用onUpdateData
完成数据修改
效果图如下
我们已经选择姓名为测试这一行数据,鼠标点击一下,弹出填充好选中行数据的表单
我们修改一下姓名:测试666;性别:女,点击提交
此时我们发现,这条数据我们已经成功修改!
到这里,我们就成功通过$emit
实现了子组件向父组件传值。我们来整理一下思路:
- 父组件自定义事件方法
@自定义事件名="方法名"
,并创建对应方法用来监听子组件的事件 - 子组件使用
$emit('父组件自定义的事件名',传递的数据)
去触发父组件自定义的事件方法,完成传值
这里有一个更简单的例子,参考其他作者文档vue中 关于$emit的用法
兄弟组件之间的通信
兄弟组件之间的通信是通过中央事件总线bus来实现的,其实这种方法可以实现父子组件、兄弟组件之间的通信,接下来简要描述一下通过事件总线bus通信
首先,创建一个空的vue实例来作为中央事件总线bus,我这里是创建了一个event.js文件,代码如下
import Vue from 'vue'
var bus = new Vue() //创建事件"中转站"
export default bus
当组件之间需要通信时,各个组件先引入这个文件,可以先将传递的数据先传给这个中转站,用法是bus.$emit('事件名',传递的数据)
,然后需要接收数据的组件使用bus.$on('自定义事件名',接收的数据)
,发送和接收的事件名必须一致。其实感觉就和子组件向父组件传值类似,只是中转了一下
事件总线bus使用完需要清除,否则会一直存在
beforeDestroy(){
bus.$off('事件名')
}
这里可以参考一下这篇其他作者文档vue中央事件总线eventBus的简单理解和使用
关于组件之间的通信暂时就学习到这里,如果内容有问题,欢迎指正,谢谢!