2021-07-13 父子组件、兄弟组件之间的通信问题

说在前面

  这篇文章是以前写的,略微有些冗余与复杂,简约整理请看这篇文章:父组件向子组件通信与子组件向父组件通信问题总结

父组件向子组件传值

  父组件向子组件传值主要是通过props来实现的(或者另一种说法:子组件通过props来接收父组件传递的值。更好理解),需要注意的是,props是单向绑定,后文将会说明这个属性。眼过千遍不如手过一遍,接下来将通过两个实例来展现props是如何实现父组件向子组件传值的

  1. 首先定义一个父组件,命名为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实现了子组件向父组件传值。我们来整理一下思路:

  1. 父组件自定义事件方法@自定义事件名="方法名",并创建对应方法用来监听子组件的事件
  2. 子组件使用$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的简单理解和使用

  关于组件之间的通信暂时就学习到这里,如果内容有问题,欢迎指正,谢谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这都能重名?!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值