组件之间的通信方式 - 图1

1. 父子组件传值

1.1 props

父组件可以把子级的属性和方法传给子组件, 子组件需要在props里面接收, 即可使用。props可以是数组类型, 也可以是对象类型。 :::success //父组件

//子组件
props:{
parentData:[‘parentData’,’getData’]
}, :::

  1. //父组件
  2. <template>
  3. <div class="parent" >
  4. <h2>我是父组件</h2>
  5. <h2>姓名:{{parentData.name}}</h2>
  6. <h2>年龄:{{parentData.age}}</h2>
  7. <my-child :parentData="parentData" :getData="getData"></my-child>
  8. </div>
  9. </template>
  10. <script>
  11. import MyChild from './MyChild.vue'
  12. export default {
  13. components: {
  14. MyChild,
  15. },
  16. data() {
  17. return {
  18. parentData: {
  19. name: '我是父组件',
  20. age:'60'
  21. },
  22. getData(){
  23. console.log('我是父组件的getData方法')
  24. }
  25. }
  26. },
  27. }
  28. </script>
  29. //子组件
  30. <template>
  31. <div class="child">
  32. <h2>我是子元素</h2>
  33. <h3>姓名:{{child.name}}</h3>
  34. <h3>年龄:{{child.age}}</h3>
  35. <button @click="getDataByParent">通过$parent获取父组件数据</button>
  36. <button @click="getData">通ss</button>
  37. <my-son v-bind="$attrs"></my-son>
  38. </div>
  39. </template>
  40. <script>
  41. import MySon from './MySon.vue'
  42. export default {
  43. components: {
  44. MySon,
  45. },
  46. props:{
  47. parentData:{
  48. type:Object,
  49. required: true,
  50. default: function() {
  51. return { name:'我是默认值', age:20 };
  52. }
  53. },
  54. getData:{
  55. type:Function
  56. }
  57. },
  58. data() {
  59. return {
  60. child: {
  61. name: '我是child组件',
  62. age: 45,
  63. },
  64. }
  65. },
  66. methods: {
  67. getDataByParent() {
  68. console.log(this.parentData)
  69. },
  70. },
  71. }
  72. </script>

1.2 $emit

子组件可以通过this.$emit把子级的数据给父组件。 :::success //父组件

//子组件
getDataByParent() {
this.$emit(‘sendMsg’,’我是子组件’)
}, :::

  1. <template>
  2. <div class="parent" >
  3. <h2>我是父组件</h2>
  4. <h2>姓名:{{parentData.name}}</h2>
  5. <h2>年龄:{{parentData.age}}</h2>
  6. <my-child @sendMsg = 'sendMsg'></my-child>
  7. </div>
  8. </template>
  9. <script>
  10. import MyChild from './MyChild.vue'
  11. export default {
  12. components: {
  13. MyChild,
  14. },
  15. data() {
  16. return {
  17. parentData: {
  18. name: '我是父组件',
  19. age:'60'
  20. },
  21. getData(){
  22. console.log('我是父组件的getData方法')
  23. }
  24. }
  25. },
  26. methods:{
  27. sendMsg(val){
  28. console.log(val)
  29. }
  30. }
  31. }
  32. </script>
  33. //子组件
  34. <template>
  35. <div class="child">
  36. <h2>我是子元素</h2>
  37. <h3>姓名:{{child.name}}</h3>
  38. <h3>年龄:{{child.age}}</h3>
  39. <button @click="getDataByParent">send</button>
  40. <my-son v-bind="$attrs"></my-son>
  41. </div>
  42. </template>
  43. <script>
  44. import MySon from './MySon.vue'
  45. export default {
  46. components: {
  47. MySon,
  48. },
  49. data() {
  50. return {
  51. child: {
  52. name: '我是child组件',
  53. age: 45,
  54. },
  55. }
  56. },
  57. methods: {
  58. getDataByParent() {
  59. this.$emit('sendMsg','我是子组件')
  60. },
  61. },
  62. }
  63. </script>

1.3 $parent

子组件通过this.$parent获取父组件的属性和方法 :::success this.$parent.parentData //获取父组件的属性
this.$parent.getData() //调用父组件的方法 :::

  1. //parent组件
  2. <template>
  3. <div class="parent" ref='parentEle'>
  4. <h2>我是父组件</h2>
  5. <h2>姓名:{{parentData.name}}</h2>
  6. <h2>年龄:{{parentData.age}}</h2>
  7. <my-child></my-child>
  8. </div>
  9. </template>
  10. <script>
  11. import MyChild from './MyChild.vue'
  12. export default {
  13. components: {
  14. MyChild,
  15. },
  16. data() {
  17. return {
  18. parentData: {
  19. name: '我是父组件',
  20. age:'60'
  21. },
  22. }
  23. },
  24. }
  25. </script>
  26. //child组件
  27. <template>
  28. <div class="child">
  29. <h2>我是子元素</h2>
  30. <h3>姓名:{{child.name}}</h3>
  31. <h3>年龄:{{child.age}}</h3>
  32. <button @click="getDataByParent">通过$parent获取父组件数据</button>
  33. <my-son v-bind="$attrs"></my-son>
  34. </div>
  35. </template>
  36. <script>
  37. import MySon from './MySon.vue'
  38. export default {
  39. components: {
  40. MySon,
  41. },
  42. data() {
  43. return {
  44. child: {
  45. name: '我是child组件',
  46. age: 45,
  47. },
  48. }
  49. },
  50. methods: {
  51. getDataByParent() {
  52. console.log(this.$parent.parentData) //获取父组件的属性
  53. console.log(this.$parent.getData()) //调用父组件的方法
  54. },
  55. },
  56. }
  57. </script>

1.4 $refs

可以通过this.$refs获取子组件的属性和方法. :::success
console.log(this.$refs.childEle.child) //获取子组件的属性
console.log(this.$refs.childEle.change())//获取子组件的方法 :::

  1. <template>
  2. <div class="parent" >
  3. <h2>我是父组件</h2>
  4. <h2>姓名:{{parentData.name}}</h2>
  5. <h2>年龄:{{parentData.age}}</h2>
  6. <button @click="getData">通过ref获取子组件的数据</button>
  7. <my-child ref='childEle'></my-child>
  8. </div>
  9. </template>
  10. <script>
  11. import MyChild from './MyChild.vue'
  12. export default {
  13. components: {
  14. MyChild,
  15. },
  16. data() {
  17. return {
  18. parentData: {
  19. name: '我是父组件',
  20. age:'60'
  21. }
  22. }
  23. },
  24. methods:{
  25. getData(){
  26. console.log(this.$refs.childEle.child) //获取子组件的属性
  27. console.log(this.$refs.childEle.change())//获取子组件的方法
  28. }
  29. }
  30. }
  31. </script>

1.5 $attrs

首先我们有三个组件A-B-C,然后想A中的属性传入C中,基本的做法是这样的,一层一层通过 props 往下传递。
ComponentB 组件中并没有使用到父组件传递过来的属性 msg,但是这样写就是想把属性再传递给ComponentC,那么除了这种写法还可以给ComponentC绑定$attrs属性。

  1. <component-c v-bind="$attrs"></component-c>

1.6 $children

this.$children可以获取子组件的方法和属性。
在父组件中打印this.$children。里面包含了所有子组件:
image.png

  1. <template>
  2. <div class="parent">
  3. <h2>我是父组件</h2>
  4. <h2>姓名:{{parentData.name}}</h2>
  5. <h2>年龄:{{parentData.age}}</h2>
  6. <button>通过ref获取子组件的数据</button>
  7. <my-child :parentData="parentData"></my-child>
  8. </div>
  9. </template>
  10. <script>
  11. import MyChild from './MyChild.vue'
  12. export default {
  13. components: {
  14. MyChild,
  15. },
  16. data() {
  17. return {
  18. parentData: {
  19. name: '我是父组件',
  20. age: '60',
  21. },
  22. }
  23. },
  24. mounted() {
  25. console.log(this.$children[0].child)
  26. console.log(this.$children[0].getData())
  27. },
  28. }
  29. </script>

2. 兄弟组件传值

2.1 bus事件总线

通过this.$emit和this.$on。this.$emit触发当前实例上的事件, 并将参数传递给监听器, 通过this.$on监听当前实例上的自定义事件。 :::success 简单理解为一个托管平台, 这个平台必须独立于关联两个组件之外的vue实例, 当2个组件需要传递数据的时候, 发起方在平台上触发一个this.$emit然后传递参数, 接收方在平台设置一个监听this.$on接收参数并执行方法, 方法的参数就是发送方传递过来的参数。 :::

  1. //main.js
  2. import Vue from 'vue'
  3. import App from './App.vue'
  4. import ElementUI from 'element-ui';
  5. import Directives from './directives/index'
  6. import 'element-ui/lib/theme-chalk/index.css';
  7. import store from './store'
  8. Vue.use(Directives)
  9. Vue.config.productionTip = false;
  10. Vue.use(ElementUI);
  11. const vm = new Vue({
  12. render: h => h(App),
  13. store,
  14. beforeCreate(){
  15. Vue.prototype.$bus = this;
  16. }
  17. }).$mount('#app')
  18. console.log(vm)
  19. //发送方
  20. this.bus.$emit('send', this.child1)
  21. //接收方
  22. this.bus.$on('send', (value) => {
  23. this.child1 = value
  24. })
  1. //兄弟一
  2. <template>
  3. <div class="child">
  4. <h2>我是子元素</h2>
  5. <h3>姓名:{{child1.name}}</h3>
  6. <h3>年龄:{{child1.age}}</h3>
  7. <button @click="sendData">给兄弟组件传值</button>
  8. <hr>
  9. </div>
  10. </template>
  11. <script>
  12. export default {
  13. data() {
  14. return {
  15. child1: {
  16. name: '我是child1111组件',
  17. age: 45,
  18. },
  19. }
  20. },
  21. methods:{
  22. sendData(){
  23. this.bus.$emit('send', this.child1)
  24. }
  25. }
  26. }
  27. </script>
  28. <style>
  29. .child {
  30. padding: 20px;
  31. background: green;
  32. }
  33. </style>
  34. //兄弟2
  35. <template>
  36. <div class="child2">
  37. <h2>我是子元素</h2>
  38. <h3>姓名:{{child2.name}}</h3>
  39. <h3>年龄:{{child2.age}}</h3>
  40. <p>下面是兄弟组件传过来的值</p>
  41. <h2>{{child1.name}}</h2>
  42. <h2>{{child1.age}}</h2>
  43. </div>
  44. </template>
  45. <script>
  46. export default {
  47. data() {
  48. return {
  49. child2: {
  50. name: '我是child组件22222',
  51. age: 45,
  52. },
  53. child1:{}
  54. }
  55. },
  56. methods:{
  57. },
  58. mounted(){
  59. console.log(1231321)
  60. // this.bus.$on('send', this.getData)
  61. this.bus.$on('send', (value) => {
  62. this.child1 = value
  63. })
  64. }
  65. }
  66. </script>
  67. <style>
  68. .child2 {
  69. padding: 20px;
  70. background: rgb(32, 68, 230);
  71. }
  72. </style>

image.png