美文网首页
vue组件通信

vue组件通信

作者: Ni_c746 | 来源:发表于2019-12-12 16:21 被阅读0次

    vue深层的组件间通信

    需求:当我们有一个组件的层级结构为 组件1 >> 组件2 >> 组件3的时候怎样通信最好

    方案

    1. 通过最常用的props和$emit来实现组件间的传值

      缺点:随着组件的嵌套的层级增多,每层的父组件都要监听子组件$emit发射的事件,太繁琐

    2. 通过this.$parent和this.$children来相互调用组件的值或方法实现通信

      缺点:这个可以避免props和$emit的问题,但是假设我想在组件3用引用组件1的方法来改变某一个变量时,这时我们用这样写this.$parent.$parent,这样就很鸡肋,而且还必须管理父组件的层级,太不灵活

    3. 通过eventBus来实现多层组件间的数据共享

      分析:eventBus实际上就是通过将共享的变量存在新建的一个vue的实例上,然后通过该实例的$emit和$on去实现数据的传递

      代码:

          eventBus.js

          import Vue from 'vue'

          export default new Vue()

          组件1

          import bus from 'common/js/eventBus'

          export default {

            methods: {

              busEmit() {

                bus.$emit('busEmit', '我是组件1发送的值')

              }

            },

            created() {

              this.busEmit()

            }

          }

          组件3

          import bus from 'common/js/eventBus'

          export default {

            created() {

              bus.$on('busEmit', (data) => {

                console.log(data)

              })

            }

          }

      优势:对于某一个多层嵌套的组件而言,他不会太繁琐

      缺点:但是对于有多个这种组件都要做多层件的传值时,由于所有共享值都是有这一个vue的实例去发送的,因此这种方案就不利于项目后期的状态维护,且耦合度也比较高

    4. 通过vuex这个状态管理来共享数据

      分析:vuex可能是最常用的跨组件和跨页面的通信方式了,它相比于eventBus的方案,由于它可以将不同模块的数据进行模块化管理,通过namespace的方式访问,这使得其可维护性相对于前者比较高,并且也降低了数据转态之间的耦合

      缺点:假设如果有上百个组件都是这种嵌套的情况,那vuex也就要维护这些组件的一些数据和状态,组件内部要不停的去通过mutations,actions操作数据的变化,写法上就太麻烦了

    5. 通过provide/inject来跨组件通信

      代码

          组件A

          <template>

            <div>

              {{name}}-{{age}}

              <b-comp />

            </div>

          </template>

          <script>

          import BComp from './b.vue'

          export default {

            provide() {

              return {

                compA: this,

                compA_age: this.age

              }

            },

            data() {

              return {

                name: '我是组件A',

                age: 18

              }

            },

            components: {

              BComp

            },

            methods: {

              test() {

                console.log('我是a组件的测试方法')

              }

            }

          }

          </script>

          组件b

          <template>

            <div>

              {{name}}

              <c-comp />

            </div>

          </template>

          <script>

          import CComp from './c.vue'

          export default {

            provide() {

              return {

                compB_name: this.name,

                compB: this

              }

            },

            inject: {

              getCompAdata: {

                from: 'compA',

                default: null

              },

              getCompAage: {

                from: 'compA_age',

                default: 19

              }

            },

            data() {

              return {

                name: '我是组件B'

              }

            },

            components: {

              CComp

            },

            created() {

              console.log(this.getCompAdata.name)

              this.getCompAdata.test()

              console.log(this.getCompAage) // 如果a组件中没有compA_age则会显示19

              this.getCompAdata.name = '我是组件A change by CompB' // 修改会影响a组件,和props传入对象一样,但是会抛出警告,证明他与props一样数据是单向传递的

              this.getCompAage = '18 change by CompB'

            }

          }

          </script>

          组件c

          <template>

            <div>

              我是组件C

            </div>

          </template>

          <script>

          export default {

            inject: {

              getCompB_name: {

                from: 'compB_name',

                default: ''

              },

              getCompB: {

                from: 'compB',

                default: ''

              },

              getCompA: {

                from: 'compA',

                default: ''

              }

            },

            data() {

              return {

                name: 'C'

              }

            },

            created() {

              console.log('c组件访问b组件的name属性:', this.getCompB_name)

              console.log('c组件访问b组件的this对象:', this.getCompB)

              console.log('c组件访问b组件的this对象调用组件A的name:', this.getCompB.getCompAdata.name)

              console.log('c组件访问a组件的name:', this.getCompA.name)

            }

          }

          </script>

      总结:这钟是目前来说比较好的方式,因为每个嵌套组件的状态是相对独立的,由他们自身去控制和维护,在写法上也比较简单,并且可以通过from字段定义引用的来源,以此来减少耦合

    6. 在组件中使用inheritAttrs和$attrs传递数据

          组件a

          <template>

            <div>

              {{name}}-{{age}}-stars:{{obj.star}}

              <b-comp :name="name" :obj="obj" :age="age" :test="test"/>

            </div>

          </template>

          <script>

          import BComp from './b.vue'

          export default {

            data() {

              return {

                name: '我是组件A',

                age: 18,

                obj: {

                  star: 2300

                }

              }

            },

            components: {

              BComp

            },

            methods: {

              test() {

                console.log('我是a组件的测试方法')

              }

            }

          }

          </script>

          组件b

          <template>

            <div>

              {{name}}

              <c-comp :name="name" v-bind="$attrs"/>

            </div>

          </template>

          <script>

          import CComp from './c.vue'

          export default {

            inheritAttrs: false,

            data() {

              return {

                name: '我是组件B'

              }

            },

            components: {

              CComp

            },

            created() {

              console.log('组件b', this.$attrs)

              this.$attrs.test()

              this.$attrs.obj.star = 4000

              this.$attrs.age = 100

            }

          }

          </script>

          组件c

          <template>

            <div>

              我是组件C

            </div>

          </template>

          <script>

          export default {

            inheritAttrs: false,

            props: {

              obj: {

                type: Object,

                default() {

                  return {}

                }

              }

            },

            data() {

              return {

                name: 'C'

              }

            },

            created() {

              console.log('组件c的',this.$attrs)

            }

          }

          </script>

      总结:

      这种方式值的传递也是单向的,当传递一个引用类型的数据是,在子组件修改此参数数据,也会影响父级组件,但是它不会报错,当你传入的参数与子组件内部的props同名是,此时的$attrs会将该重复的数据去除掉,如果你中间的组件传一个名字相同的参数时,此时后面的会覆盖前面的同名参数的值。

    [vue.md](./upload/201911/23/15744928021101847029.md)

    相关文章

      网友评论

          本文标题:vue组件通信

          本文链接:https://www.haomeiwen.com/subject/xlytnctx.html