0


vue组件通信

父组件传值给子组件:props $parent

子组件传值给父组件:$emit $refs $children

$attrs 进行跨层级传值,比如,爷爷组件传值孙子组件

$listeners 孙子传值爷爷

slot 插槽传值

bus 任意组件传值

路由传参

vuex

==================================================================================================================================================

1,父组件传值子组件 props

子组件有时候需要接收来自父组件的数据,这时候就需要给子组件绑定props的值,

props表示期待的获取的数据

步骤:

1、创建父子组件

2、在子组件组件中添加props属性,值可以是数组或者对象形式,

  1. // 子组件
  1. components: {
  2. son:{
  3. template:'#s',
  4. // 1、props定义在子组件中,表示期望接收到的值
  5. // props中接收到的值,可以像data中的值一样自由调用
  6. props: ['txt'],
  7. data(){
  8. return{
  9. msg:'我是子组件数据'
  10. }
  11. }
  12. }
  13. }

3、父组件给子组件传值

在调用子组件的地方 以组件自定义标签属性的方式传递数据

下图中实例的txt,就是上面props中添加的属性

  1. <!--2、 在调用子组件的地方 以组件自定义标签属性的方式传递数据 -->
  2. <!-- 直接属性名 = '具体的值 ,会把具体的值直接传过去,写死了' -->
  3. <!-- <son txt='info'></son> -->
  4. <!-- 动态绑定传递的数据 -->
  5. <son v-bind:txt="info"></son>

此时,给子组件传递的值,在子组件模板中,可以像调用data数据一样调用

  1. <!-- 子组件 模板 -->
  2. <template id="s">
  3. <div class="son">
  4. {{msg}}
  5. <!-- 3、子元素中调用props的值 -->
  6. <h4>{{txt}}</h4>
  7. </div>
  8. </template>

示例:

  1. <style>
  2. .father{
  3. width: 500px;
  4. height: 400px;
  5. background-color: rgb(218, 105, 105);
  6. }
  7. .son{
  8. width: 300px;
  9. height: 200px;
  10. background-color: rgb(112, 97, 97);
  11. margin: 50px auto;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <div id ="app">
  17. <father> </father>
  18. </div>
  19. <!-- 父组件 模板 -->
  20. <template id="f">
  21. <div class="father">
  22. {{msg}}
  23. <!--2、 在调用子组件的地方 以组件自定义标签属性的方式传递数据 -->
  24. <!-- 直接属性名 = '具体的值 ,会把具体的值直接传过去,写死了' -->
  25. <!-- <son txt='info'></son> -->
  26. <!-- 动态绑定传递的数据 -->
  27. <son v-bind:txt="info"></son>
  28. </div>
  29. </template>
  30. <!-- 子组件 模板 -->
  31. <template id="s">
  32. <div class="son">
  33. {{msg}}
  34. <!-- 3、子元素中调用props的值 -->
  35. <h4>{{txt}}</h4>
  36. </div>
  37. </template>
  38. <script>
  39. //创建Vue实例,得到 ViewModel
  40. var vm = new Vue({
  41. el: '#app',
  42. data: {},
  43. methods: {},
  44. // 父组件
  45. components: {
  46. father:{
  47. template:'#f',
  48. data(){
  49. return{
  50. msg:'我是父组件的数据',
  51. info:'我是父组件中即将传递给子组件的值'
  52. }
  53. },
  54. // 子组件
  55. components: {
  56. son:{
  57. template:'#s',
  58. // 1、props定义在子组件中,表示期望接收到的值
  59. // props中接收到的值,可以像data中的值一样自由调用
  60. props: ['txt'],
  61. data(){
  62. return{
  63. msg:'我是子组件数据'
  64. }
  65. }
  66. }
  67. }
  68. }
  69. }
  70. });
  71. </script>
  72. </body>

结果:

2,子组件传值给父组件 $emit

  1. #子组件中
  2. this.$emit(‘event’,val);
  3. //$emit:实例方法,用来触发事件监听
  4. //参数
  5. event:自定义事件名称
  6. val:通过自定义事件传递的值(val为可选参数)
  7. #子组件主动触发事件监听 (抛)
  8. <button @click="go">向父组件传值</button>
  9. methods:{
  10. go(){
  11. this.$emit('自定义事件名',事件传递的可选参数);
  12. }
  13. }
  14. #父组件中接收自定义事件监听 (接)
  15. <component @自定义事件名='事件处理函数/fn'></component>
  16. methods:{
  17. fn(v){
  18. v//自定义事件传递的值,会作为fn的参数来传递
  19. }
  20. }

1、编写父子组件

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <script src="../lib/vue.js"></script>
  9. <style>
  10. .father{
  11. width: 500px;
  12. height: 400px;
  13. background-color: rgb(218, 105, 105);
  14. }
  15. .son{
  16. width: 300px;
  17. height: 200px;
  18. background-color: rgb(112, 97, 97);
  19. margin: 50px auto;
  20. }
  21. </style>
  22. </head>
  23. <body>
  24. <div id ="app">
  25. <father> </father>
  26. </div>
  27. <!-- 父组件 模板 -->
  28. <template id="f">
  29. <div class="father">
  30. {{msg}}
  31. <son></son>
  32. </div>
  33. </template>
  34. <!-- 子组件 模板 -->
  35. <template id="s">
  36. <div class="son">
  37. {{msg}}
  38. </div>
  39. </template>
  40. <script>
  41. //创建Vue实例,得到 ViewModel
  42. var vm = new Vue({
  43. el: '#app',
  44. data: {},
  45. methods: {},
  46. // 父组件
  47. components: {
  48. father:{
  49. template:'#f',
  50. data(){
  51. return{
  52. msg:'我是父组件的数据',
  53. }
  54. },
  55. // 子组件
  56. components: {
  57. son:{
  58. template:'#s',
  59. data(){
  60. return{
  61. msg:'我是子组件数据',
  62. info:'我是子组件将要传递个父组件的值'
  63. }
  64. }
  65. }
  66. }
  67. }
  68. }
  69. });
  70. </script>
  71. </body>
  72. </html>

2、在子组件模板中编写给父组件传值的按钮 绑定点击事件

  1. <!-- 子组件 模板 -->
  2. <template id="s">
  3. <div class="son">
  4. <p>{{msg}}</p>
  5. #<!-- 1、子组件中添加一个给父组件传值的按钮 -->
  6. <button @click='change'>给父组件传值</button>
  7. </div>
  8. </template>

3、编写子组件中传值的方法

  1. // 子组件
  2. components: {
  3. son:{
  4. template:'#s',
  5. data(){
  6. return{
  7. msg:'我是子组件数据',
  8. info:'我是子组件将要传递个父组件的值'
  9. }
  10. },
  11. // 2、在子组件中添加方法,给父组件传值的方法
  12. methods:{
  13. change(){
  14. this.$emit('to_father',this.info);
  15. }
  16. }
  17. }
  18. }

3、在父组件调用子组件的位置,监听自定义事件

  1. <!-- 父组件 模板 -->
  2. <template id="f">
  3. <div class="father">
  4. {{msg}}
  5. #<!-- 3、父组件接收传值 监听自定义的事件 执行对应函数 接下来编写函数-->
  6. <son @to_father='accept_'></son>
  7. </div>
  8. </template>

4、父组件中编写监听事件对应的方法

  1. methods:{
  2. accept_(v){
  3. console.log(v);
  4. }
  5. },

3,通过refs进行组件传值 子组件传值给父组件

1、ref 加在普通的元素上,用this.$refs.ref值 , 获取到的是dom元素。

2、ref 加在子组件上,用this.$refs.ref值 , 获取到的是组件实例,可以使用组件的所有方法、属性。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <style>
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. }
  13. html,
  14. body,
  15. #app {
  16. width: 100%;
  17. height: 100%;
  18. }
  19. .fatherBox {
  20. width: 100%;
  21. height: 100%;
  22. background-color: rgb(253, 234, 234);
  23. padding: 20px;
  24. box-sizing: border-box;
  25. }
  26. .sonBox {
  27. width: 50%;
  28. height: 200px;
  29. background-color: rgb(241, 209, 28);
  30. padding: 20px;
  31. box-sizing: border-box;
  32. margin: 20px 0;
  33. }
  34. </style>
  35. </head>
  36. <body>
  37. <div id="app">
  38. <Father></Father>
  39. </div>
  40. <template id="father">
  41. <div class="fatherBox">
  42. <h2>欢迎来到父组件</h2>
  43. <p>父组件将要接收子组件传递的值:{{msg}}</p>
  44. <br>
  45. <button @click="getRef">借助ref获取子组件的值</button>
  46. <!-- ref 写在组件上 指向当前组件 可以获取到当前组件一切内容 -->
  47. <Son ref="son"></Son>
  48. </div>
  49. </template>
  50. <!--子组件模板 -->
  51. <template id="son">
  52. <div class="sonBox">
  53. <h2>欢迎来到子组件</h2>
  54. <p>将要孝敬爸爸的礼物:{{gift1}}</p>
  55. <p>将要孝敬爸爸的礼物:{{gift2}}</p>
  56. </div>
  57. </template>
  58. </body>
  59. </html>
  60. <script src="./js/vue.js"></script>
  61. <script>
  62. //创建Vue实例,得到 ViewModel
  63. var vm = new Vue({
  64. el: '#app',
  65. data: {},
  66. methods: {},
  67. components: {
  68. Father: {
  69. template: '#father',
  70. data() {
  71. return {
  72. msg: null,
  73. }
  74. },
  75. methods: {
  76. getRef() {
  77. console.log(this.$refs.son.gift1);
  78. this.msg = this.$refs.son.gift1;
  79. }
  80. },
  81. components: {
  82. Son: {
  83. template: '#son',
  84. data() {
  85. return {
  86. gift1: '茅台',
  87. gift2: '华子'
  88. }
  89. },
  90. }
  91. }
  92. }
  93. }
  94. });
  95. </script>

4,通过$parent 进行父子传值

this.$parent,可以获取到当前组件的父组件实例,

即,可以直接调用使用父组件内的方法、属性、一切

例:

this.$parent.$parent.msg // 获取当前组件的父组件中的msg值

方法调用同理

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <style>
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. }
  13. html,
  14. body,
  15. #app {
  16. width: 100%;
  17. height: 100%;
  18. }
  19. .fatherBox {
  20. width: 100%;
  21. height: 100%;
  22. background-color: rgb(253, 234, 234);
  23. padding: 20px;
  24. box-sizing: border-box;
  25. }
  26. .sonBox {
  27. width: 50%;
  28. height: 200px;
  29. background-color: rgb(241, 209, 28);
  30. padding: 20px;
  31. box-sizing: border-box;
  32. margin: 20px 0;
  33. }
  34. </style>
  35. </head>
  36. <body>
  37. <div id="app">
  38. <Father></Father>
  39. </div>
  40. <template id="father">
  41. <div class="fatherBox">
  42. <h2>欢迎来到父组件</h2>
  43. <p>父组件将要接收子组件传递的值:{{msg}}</p>
  44. <br>
  45. <Son></Son>
  46. </div>
  47. </template>
  48. <!--子组件模板 -->
  49. <template id="son">
  50. <div class="sonBox">
  51. <h2>欢迎来到子组件</h2>
  52. <p>将要获取父组件的内容:{{getFather}}</p>
  53. <button @click="getParent">获取父组件</button>
  54. </div>
  55. </template>
  56. </body>
  57. </html>
  58. <script src="./js/vue.js"></script>
  59. <script>
  60. //创建Vue实例,得到 ViewModel
  61. var vm = new Vue({
  62. el: '#app',
  63. data: {
  64. msg: 'app中的数据'
  65. },
  66. methods: {
  67. },
  68. components: {
  69. Father: {
  70. template: '#father',
  71. data() {
  72. return {
  73. msg: '父组件的值',
  74. }
  75. },
  76. methods: {
  77. },
  78. components: {
  79. Son: {
  80. template: '#son',
  81. data() {
  82. return {
  83. getFather: ''
  84. }
  85. },
  86. methods: {
  87. getParent() {
  88. console.log(this);
  89. //通过this.$parent 可以获取到整个父组件 把父组件的值 转存一下 就可以了
  90. console.log(this.$parent);
  91. console.log(this.$parent.msg);//父组件的值
  92. this.getFather = this.$parent.msg;
  93. }
  94. }
  95. }
  96. }
  97. }
  98. }
  99. });
  100. </script>

5,通过$children 进行子组件传值父组件

vm.$children可以获取到所有的子组件

以数组形式展现,可以通过下标获取对应组件的实例属性方法。。。

使用子传父: 父组件通过$children,获取到对应子组件的值,把值转存到自己的data中,完成传值

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>$children</title>
  8. <style>
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. }
  13. html,
  14. body,
  15. #app {
  16. width: 100%;
  17. height: 100%;
  18. }
  19. .fatherBox {
  20. width: 100%;
  21. height: 100%;
  22. background-color: rgb(253, 234, 234);
  23. padding: 20px;
  24. box-sizing: border-box;
  25. }
  26. .sonBox {
  27. width: 50%;
  28. height: 200px;
  29. background-color: rgb(241, 209, 28);
  30. padding: 20px;
  31. box-sizing: border-box;
  32. margin: 20px 0;
  33. }
  34. </style>
  35. </head>
  36. <body>
  37. <div id="app">
  38. <Father></Father>
  39. </div>
  40. <template id="father">
  41. <div class="fatherBox">
  42. <h1>Father组件</h1>
  43. <p>Faher组件将要传递给子组件的值:{{msg}}</p>
  44. <button @click="get">获取子组件值</button>
  45. <Son></Son>
  46. </div>
  47. </template>
  48. <template id="son">
  49. <div class="sonBox">
  50. <h1>Son组件</h1>
  51. <p>son组件将要传给父组件的值:{{info}}</p>
  52. </div>
  53. </template>
  54. </body>
  55. </html>
  56. <script src="./js/vue.js"></script>
  57. <script>
  58. let Son = {
  59. template: "#son",
  60. data() {
  61. return {
  62. info: '孝敬爸爸的礼物'
  63. }
  64. }
  65. }
  66. let Father = {
  67. template: '#father',
  68. data() {
  69. return {
  70. msg: ''
  71. }
  72. },
  73. methods: {
  74. get() {
  75. console.log('chufa');
  76. console.log(this.$children);//获取到所有的子组件 按下标取对应的子组件
  77. console.log(this.$children[0].info);
  78. this.msg = this.$children[0].info;
  79. }
  80. },
  81. components: {
  82. Son
  83. }
  84. }
  85. //创建Vue实例,得到 ViewModel
  86. var vm = new Vue({
  87. el: '#app',
  88. data: {},
  89. methods: {},
  90. components: {
  91. Father
  92. }
  93. });
  94. </script>

利用watch监听,当子组件数据发生变化的时候,立马把值传递给父组件

思路: 监听子组件的数据,当变化的时候,利用this.$parent调用父组件获取子组件值的方法

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>$children</title>
  8. <style>
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. }
  13. html,
  14. body,
  15. #app {
  16. width: 100%;
  17. height: 100%;
  18. }
  19. .fatherBox {
  20. width: 100%;
  21. height: 100%;
  22. background-color: rgb(253, 234, 234);
  23. padding: 20px;
  24. box-sizing: border-box;
  25. }
  26. .sonBox {
  27. width: 50%;
  28. height: 200px;
  29. background-color: rgb(241, 209, 28);
  30. padding: 20px;
  31. box-sizing: border-box;
  32. margin: 20px 0;
  33. }
  34. </style>
  35. </head>
  36. <body>
  37. <div id="app">
  38. <Father></Father>
  39. </div>
  40. <template id="father">
  41. <div class="fatherBox">
  42. <h1>Father组件</h1>
  43. <p>Faher组件将要传递给子组件的值:{{msg}}</p>
  44. <button @click="get">获取子组件值</button>
  45. <Son></Son>
  46. </div>
  47. </template>
  48. <template id="son">
  49. <div class="sonBox">
  50. <h1>Son组件</h1>
  51. <!-- 数据变化立马传递 -->
  52. <input type="text" v-model="info">
  53. <p>son组件将要传给父组件的值:{{info}}</p>
  54. </div>
  55. </template>
  56. </body>
  57. </html>
  58. <script src="./js/vue.js"></script>
  59. <script>
  60. let Son = {
  61. template: "#son",
  62. data() {
  63. return {
  64. info: '孝敬爸爸的礼物'
  65. }
  66. },
  67. watch: {
  68. //监听数据 发现变化了,立即调用父组件的获取子组件值的方法
  69. info: {
  70. handler(newVal) {
  71. console.log('监听到了');
  72. console.log(this);
  73. console.log(this.$parent.get());
  74. },
  75. //立即监听
  76. immediate: true
  77. }
  78. }
  79. }
  80. let Father = {
  81. template: '#father',
  82. data() {
  83. return {
  84. msg: ''
  85. }
  86. },
  87. methods: {
  88. get() {
  89. console.log('chufa');
  90. console.log(this.$children);//获取到所有的子组件 按下标取对应的子组件
  91. console.log(this.$children[0].info);
  92. this.msg = this.$children[0].info;
  93. }
  94. },
  95. components: {
  96. Son
  97. }
  98. }
  99. //创建Vue实例,得到 ViewModel
  100. var vm = new Vue({
  101. el: '#app',
  102. data: {},
  103. methods: {},
  104. components: {
  105. Father
  106. }
  107. });
  108. </script>

6,vue2.6以后插入具名插槽不包含2.60!!!!!!!!

  1. 插口:
  2. // <template v-slot:usb>
  3. <template #usb>
  4. <p>插入usb</p>
  5. <p>哈哈哈,开心</p>
  6. </template>
  7. 插槽:
  8. <slot name='usb'></slot>

7,$attrs进行爷孙传值

v-bind='$attrs'

个人理解: 爷爷传值给孙子 爸爸作为中介 如果爸爸拦截了(用props接收) 就传不到孙子那里了

  1. $attrs

是在vue的2.40版本以上添加的。是一个包含组件透传属性的对象

所谓的组件透传属性,就是非属性特性,透传给内部的子组件

作用:进行跨层级传值,比如,爷爷组件传值孙子组件

应用场景:爷爷组件传值孙子组件

传统的爷爷组件传值孙子组件,我们可以使用爷爷——> 爸爸——>孙子

即:爷爷组件传值给父组件,父组件接受后,再次传值给孙子组件

这样的方式可以完成,但是太过繁琐。我们可以利用$attrs进行

使用方式:

  • 爷爷组件把想要传递给孙子组件的值,通过自定义属性值的方式,即传统的正向传值方式,传递给父组件
  • 父组件可以通过props接受父组件想要的数据,父组件中没有使用props接受的值,可以通过$attrs传递给孙子组件
  • $attrs添加在父组件模板调用孙子组件的位置,给孙子组件添加v-bind='$attrs',
  • 孙子组件在自己的组件中,使用props,接收爷爷组件传递给父组件的值,(父组件没有用pros接收的值)

1、爷爷组件传递给父组件四个值

GrandFather.vue

  1. <template>
  2. <div class="about">
  3. <h1>about Page 爷爷组件</h1>
  4. <p>爷爷组件传递给父组件的值1:{{ giveVal1 }}</p>
  5. <p>爷爷组件传递给父组件的值2:{{ giveVal2 }}</p>
  6. <p>爷爷组件传递给父组件的值3:{{ giveVal3 }}</p>
  7. <p>爷爷组件传递给父组件的值4:{{ giveVal4 }}</p>
  8. <!-- 引入父亲组件 Father -->
  9. <Father
  10. :giveVal1="giveVal1"
  11. :giveVal2="giveVal2"
  12. :giveVal3="giveVal2"
  13. :giveVal4="giveVal2"
  14. ></Father>
  15. </div>
  16. </template>
  17. <script>
  18. import Father from "@/components/Father.vue";
  19. export default {
  20. props: {},
  21. data() {
  22. return {
  23. giveVal1: "传递的值1",
  24. giveVal2: "传递的值2",
  25. giveVal3: "传递的值3",
  26. giveVal4: "传递的值4",
  27. };
  28. },
  29. methods: {},
  30. components: {
  31. Child,
  32. },
  33. };
  34. </script>
  35. <style scoped lang="less">
  36. .about {
  37. width: 100%;
  38. padding: 40px;
  39. box-sizing: border-box;
  40. background-color: rgb(248, 223, 223);
  41. }
  42. </style>

2、父组件接收一个,剩余的三个不接收

在调用孙子组件的位置,添加

  1. v-bind='$attrs'

属性值

Father.vue

  1. <template>
  2. <div class="fatherBox">
  3. <h3>父亲组件</h3>
  4. <p>通过props结收的值giveVal1:{{ giveVal1 }}</p>
  5. <!-- 在子组件中 给调用孙子组件的位置 添加$attrs属性 -->
  6. <GrandChild v-bind="$attrs"></GrandChild>
  7. </div>
  8. </template>
  9. <script>
  10. import GrandChild from "@/components/GrandChild.vue";
  11. export default {
  12. //不想继承所有父组件的内容,同时也不在组件根元素dom上显示属性
  13. inheritAttrs: false,
  14. props: {
  15. giveVal1: {
  16. type: String,
  17. },
  18. },
  19. data() {
  20. return {};
  21. },
  22. methods: {},
  23. components: {
  24. GrandChild,
  25. },
  26. };
  27. </script>
  28. <style scoped lang="less">
  29. .fatherBox {
  30. width: 80%;
  31. padding: 20px;
  32. box-sizing: border-box;
  33. margin: 0 auto;
  34. background-color: orange;
  35. }
  36. </style>

3、孙子组件使用props接收值

孙子组件使用props,接受爷爷组件传递的,没有被父组件的props接受的值

GrandChild.vue

  1. <template>
  2. <div class="grandChildBox">
  3. <h4>孙子组件</h4>
  4. <p>孙子组件接收爷爷的值1:{{ giveVal1 }}</p>
  5. <p>孙子组件接收爷爷的值2:{{ giveVal2 }}</p>
  6. <p>孙子组件接收爷爷的值3:{{ giveVal3 }}</p>
  7. <p>孙子组件接收爷爷的值4:{{ giveVal4 }}</p>
  8. </div>
  9. </template>
  10. <script>
  11. export default {
  12. props: {
  13. giveVal1: {
  14. type: String,
  15. },
  16. giveVal2: {
  17. type: String,
  18. },
  19. giveVal3: {
  20. type: String,
  21. },
  22. giveVal4: {
  23. type: String,
  24. },
  25. },
  26. data() {
  27. return {};
  28. },
  29. methods: {},
  30. components: {},
  31. };
  32. </script>
  33. <style scoped lang="less">
  34. .grandChildBox {
  35. width: 80%;
  36. padding: 20px;
  37. box-sizing: border-box;
  38. margin: 0 auto;
  39. background-color: white;
  40. }
  41. </style>

4、核心原理

使用$attrs的核心,是爷爷组件传递给父亲组件的值,父亲组件如果没有使用props接受,则会作为一个dom属性显示在页面中。

也就是说,上面例子中,所有没有被父亲组件props接收的值,全部都作为了一个dom节点的属性值展示在页面中,如下图所示:

所以,父亲组件在调用孙子组件的位置,绑定的v-bind='$attrs',其实就是把父组件自身所有的属性,正向传值给孙子组件

所以,孙子组件可以通过props接受父组件没有使用props接收的值。

那么问题来了

传值你随便传,能不能不要在页面显示父亲组件没有使用props接受的值呢,看起来太乱了

简单

在Father.vue组件的js位置,书写一个属性

8,$listeners 孙子传值爷爷

使用方法:

1、孙子组件自定义事件传值,传给上级组件

2、在父组件中 ,给调用孙子组件的位置 添加

  1. v-on="$listeners"

3、爷爷组件中,在调用父亲组件的位置,监听孙子组件的自定义事件,取值

1、孙子组件进行自定义事件传值

孙子组件使用自定义事件this.$emit传值给爷爷组件

GrandChild.vue组件

  1. <template>
  2. <div class="grandChildBox">
  3. <h4>孙子组件</h4>
  4. <p>孙子组件将要传给爷爷的值:{{ gift }}</p>
  5. <button @click="change">传值给爷爷</button>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. props: {},
  11. data() {
  12. return {
  13. gift: "茅台",
  14. };
  15. },
  16. methods: {
  17. change() {
  18. this.$emit("changeGift", this.gift);
  19. },
  20. },
  21. components: {},
  22. };
  23. </script>
  24. <style scoped lang="less">
  25. .grandChildBox {
  26. width: 80%;
  27. padding: 20px;
  28. box-sizing: border-box;
  29. margin: 0 auto;
  30. background-color: white;
  31. }
  32. </style>

2、父亲组件调用孙子组件的位置,添加v-on="$listeners"

在父组件中 给调用孙子组件的位置 添加v-on="$listeners"

Father.vue

  1. <template>
  2. <div class="fatherBox">
  3. <h3>父亲组件</h3>
  4. <!-- 在父组件中 给调用孙子组件的位置 添加v-on="$listeners" -->
  5. <GrandChild v-on="$listeners"></GrandChild>
  6. </div>
  7. </template>
  8. <script>
  9. import GrandChild from "@/components/GrandChild.vue";
  10. export default {
  11. props: {},
  12. data() {
  13. return {};
  14. },
  15. methods: {},
  16. components: {
  17. GrandChild,
  18. },
  19. };
  20. </script>
  21. <style scoped lang="less">
  22. .fatherBox {
  23. width: 80%;
  24. padding: 20px;
  25. box-sizing: border-box;
  26. margin: 0 auto;
  27. background-color: orange;
  28. }
  29. </style>

3、爷爷组件,监听自定义事件

爷爷组件,在调用父亲组件的位置,监听孙子组件的自定义事件,取值

GranderFater.vue

  1. <template>
  2. <div class="about">
  3. <h1>about Page 爷爷组件</h1>
  4. <p>期待接收孙子的值:{{ gift }}</p>
  5. <!-- 引入父亲组件 Father -->
  6. <!-- 在爷爷组件引入父组件的位置,监听孙子组件的自定义事件 -->
  7. <Father @changeGift="getVal"></Father>
  8. </div>
  9. </template>
  10. <script>
  11. import Father from "@/components/Father.vue";
  12. export default {
  13. props: {},
  14. data() {
  15. return {
  16. gift: "",
  17. };
  18. },
  19. methods: {
  20. getVal(v) {
  21. this.gift = v;
  22. },
  23. },
  24. components: {
  25. Father,
  26. },
  27. };
  28. </script>
  29. <style scoped lang="less">
  30. .about {
  31. width: 100%;
  32. padding: 40px;
  33. box-sizing: border-box;
  34. background-color: rgb(248, 223, 223);
  35. }
  36. </style>

9,bus传值

bus可以用在任何组件之间的传值

举个例子,我们现在有A、B、C、D、E、F五个组件,其中,E和F是兄弟组件,D是EF的父亲、C是D的父亲,依次类推

如图:

如果我们在E组件中,使用bus完成一个组件的传值,那么E组件传递的值,在A、B、C、D、F任意一个组件中,都可以接收到,并且,可以同时接收。所以我们说,bus可以完成任意组件的传值

使用方法:

1、在main.js中全局挂载bus

2、在要传值的组件中,使用this.bus.$emit('自定义事件',要传递的值)

3、在需要接收传值的组件中,mounted钩子函数中,使用this.bus.$on('自定义事件名',(v)=>{v}) 接受传递的数据

我们先自定义6个组件完成如上图的嵌套

A.vue

  1. <template>
  2. <div class="abox">
  3. <h1>A组件,最外层的</h1>
  4. <B></B>
  5. </div>
  6. </template>
  7. <script>
  8. import B from "../components/B";
  9. export default {
  10. props: {},
  11. data() {
  12. return {};
  13. },
  14. methods: {},
  15. components: {
  16. B,
  17. },
  18. };
  19. </script>
  20. <style scoped lang="less">
  21. .abox {
  22. width: 100%;
  23. padding: 20px;
  24. background-color: #e6ddcd;
  25. color: white;
  26. }
  27. </style>

B.vue

  1. <template>
  2. <div class="bbox">
  3. <h2>B组件</h2>
  4. <C></C>
  5. </div>
  6. </template>
  7. <script>
  8. import C from "./C";
  9. export default {
  10. props: {},
  11. data() {
  12. return {};
  13. },
  14. methods: {},
  15. components: {
  16. C,
  17. },
  18. };
  19. </script>
  20. <style scoped lang="less">
  21. .bbox {
  22. width: 80%;
  23. margin: 20px auto;
  24. padding: 20px;
  25. color: white;
  26. background-color: #c9b486;
  27. }
  28. </style>

C.vue

  1. <template>
  2. <div class="cbox">
  3. <h3>C组件</h3>
  4. <D></D>
  5. </div>
  6. </template>
  7. <script>
  8. import D from "./D";
  9. export default {
  10. props: {},
  11. data() {
  12. return {};
  13. },
  14. methods: {},
  15. components: {
  16. D,
  17. }
  18. };
  19. </script>
  20. <style scoped lang="less">
  21. .cbox {
  22. width: 80%;
  23. margin: 20px auto;
  24. padding: 20px;
  25. background-color: #2b6363;
  26. }
  27. </style>

D.vue

  1. <template>
  2. <div class="dbox">
  3. <h4>D组件</h4>
  4. <E></E>
  5. <F></F>
  6. </div>
  7. </template>
  8. <script>
  9. import F from "./F";
  10. import E from "./E";
  11. export default {
  12. props: {},
  13. data() {
  14. return {};
  15. },
  16. methods: {},
  17. components: {
  18. F,
  19. E,
  20. },
  21. };
  22. </script>
  23. <style scoped lang="less">
  24. .dbox {
  25. width: 80%;
  26. margin: 20px auto;
  27. padding: 20px;
  28. color: white;
  29. background-color: #153547;
  30. }
  31. </style>

E.vue

  1. <template>
  2. <div class="ebox">
  3. <h5>E组件</h5>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. props: {},
  9. data() {
  10. return {
  11. egift: "E孝敬的茅台",
  12. };
  13. },
  14. methods: {
  15. },
  16. components: {},
  17. };
  18. </script>
  19. <style scoped lang="less">
  20. .ebox {
  21. width: 80%;
  22. margin: 20px auto;
  23. padding: 20px;
  24. color: white;
  25. background-color: #071632;
  26. }
  27. </style>

F.vue

  1. <template>
  2. <div class="ebox">
  3. <h5>F组件</h5>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. props: {},
  9. data() {
  10. return {};
  11. },
  12. methods: {},
  13. components: {},
  14. mounted() {
  15. },
  16. };
  17. </script>
  18. <style scoped lang="less">
  19. .ebox {
  20. width: 80%;
  21. margin: 20px auto;
  22. padding: 20px;
  23. color: white;
  24. background-color: #071632;
  25. }
  26. </style>

1、在main.js中全局挂载bus

  1. Vue.prototype.bus = new Vue();

main.js

  1. import Vue from 'vue'
  2. //import App from './App.vue'
  3. import A from '@/components/A.vue'
  4. import router from './router'
  5. Vue.config.productionTip = false
  6. //1、把bus属性 挂载在vue原型对象上
  7. Vue.prototype.bus = new Vue();
  8. new Vue({
  9. router,
  10. render: function (h) { return h(A) }
  11. }).$mount('#app')

2、在需要传递数据的组件中使用bus触发自定义事件

  1. this.bus.$emit('自定义事件名',要传递的值)

此处以E.vue为例

  1. <template>
  2. <div class="ebox">
  3. <h5>E组件</h5>
  4. <button @click="EChange">E要孝敬大家了</button>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. props: {},
  10. data() {
  11. return {
  12. egift: "E孝敬的茅台",
  13. };
  14. },
  15. methods: {
  16. EChange() {
  17. this.bus.$emit("ESend", this.egift);
  18. },
  19. },
  20. components: {},
  21. };
  22. </script>
  23. <style scoped lang="less">
  24. .ebox {
  25. width: 80%;
  26. margin: 20px auto;
  27. padding: 20px;
  28. color: white;
  29. background-color: #071632;
  30. }
  31. </style>

3、需要接收的组件接收,使用this.bus.$on('自定义事件名',()=>{v})

在需要结收的组件的mounted钩子函数中,使用bus监听通bus的自定义事件

  1. this.bus.$on('自定义事件名',()=>{v})

此处以A.vue组件为例

  1. <template>
  2. <div class="abox">
  3. <h1>A组件,最外层的</h1>
  4. <B></B>
  5. </div>
  6. </template>
  7. <script>
  8. import B from "../components/B";
  9. export default {
  10. props: {},
  11. data() {
  12. return {};
  13. },
  14. methods: {},
  15. components: {
  16. B,
  17. },
  18. mounted() {
  19. this.bus.$on("ESend", (v) => {
  20. console.log("a接收E孝敬的:", v);
  21. });
  22. },
  23. };
  24. </script>
  25. <style scoped lang="less">
  26. .abox {
  27. width: 100%;
  28. padding: 20px;
  29. background-color: #e6ddcd;
  30. color: white;
  31. }
  32. </style>

在c组件,F组件中如法炮制,同样的写法

当我们触发E组件传值时,神奇的现象来了:

太厉害了,那么问题来了,是不是只能子组件通过bus传递给父组件和兄弟组件,

父组件可以通过这样的方法传递给子组件吗??

注意!!!!!!!!!!!!!!!!

我们说,bus是什么?可以进行任意组件的传值,所以,答案是,没问题

自己写代码,测试一下


本文转载自: https://blog.csdn.net/qq_46376192/article/details/128501853
版权归原作者 青青子衿越 所有, 如有侵权,请联系我们删除。

“vue组件通信”的评论:

还没有评论