一文将带你了解Vue中组件化通讯方式

376 阅读1分钟

前言

  • Vue提供了各种各样的通讯,其中包括兄弟间的通讯和非兄弟间的通讯以及后代之间的通讯,接下来就让我们一一解析吧。如果有喜欢的话可以点赞👍或者关注一下。

目标

  • 学习Vue中的组件化通讯方式。

通讯方式

  1. props

    • 功能说明

      • 父组件和子组件传递数据
    • 目录结构

      components
         ├── Parent.vue
         ├── Child.vue
      
    • 代码结构

      父组件中使用子组件并传给子组件值。foo="foo"

      <template>
        <div>
          parent comp
          <Child foo="foo" />
        </div>
      </template>
      <script>
        import Child from './child'
        export default {
          components: {
            Child
          },
        }
      </script>
      

      子组件通过props接收父组件传过来的值

      <template>
        <div>
          child comp
          {{ foo }}
        </div>
      </template>
      <script>
        export default {
          props: {
            foo: {
              type: String,
              default: ''
            },
          },
        }
      </script>
      
  2. emit/on

    • 功能说明

      • 子组件给父组件传值
    • 目录结构

      components
         ├── Parent.vue
         ├── Child.vue
      
    • 代码结构

      子组件通过$emit触发父组件的方法 ,通过回调参数的方式进行传值

      <template>
        <div>
          child comp
          <button @click="add">child 点击</button>
        </div>
      </template>
      <script>
        export default {
          methods: {
            add() {
              this.$emit('add', 'child add message')
            },
          }
        }
      </script>
      

      父组件给子组件绑定一个自定义方法$on,接收回调参数。

      <template>
        <div>
          parent comp
          <Child @add="add"/>
        </div>
      </template>
      ​
      <script>
      import Child from './child'
      export default {
        methods: {
          add(message) {
            console.log(message) // 打印child add message
          }
        },
        components: {
          Child
        },
      }
      </script>
      
  3. event bus事件总线

    • 功能说明

      • Event Bus 可用于跨组件通知(简单项目可以使用这种方式)
    • 实现方式

      • 第一种直接使用Vue作用事件总线来使用

        Vue.prototype.$bus = new Vue()
        
      • 第二种自定义实现

        // 自定义Bus
        class Bus {
          constructor() {
            this.callbacks = {}
          }
        ​
          $on(name, fn) {
            this.callbacks[name] = this.callbacks[name] || []
            this.callbacks[name].push(fn)
          }
        ​
          $emit(name, args) {
            if (this.callbacks[name]) {
              this.callbacks[name].forEach((cb) => cb(args))
            }
          }
        }
        ​
        export default Bus
        
    • 目录结构

      main.js
      components
         ├── Parent.vue
         ├── Goundson.vue
      
    • 代码结构

      main.js

      Vue.prototype.$bus = new Vue()
      

      Goundson.vue,组件使用$emit发送addbus方法并携带参数

      <template>
        <div>
          goundson comp
          <button @click="addBus">bus goundson click</button>
        </div>
      </template>
      ​
      <script>
        export default {
          methods: {
            addBus() {
              this.$bus.$emit('addbus', 'add bus message')
            }
          },
        }
      </script>
      

      Parent.vue 组件使用$on接收addbus方法并接收参数

      <template>
        <div>
          parent comp
        </div>
      </template>
      ​
      <script>
      export default {
        mounted() {
          this.$bus.$on('addbus', (message) => {
            console.log(message) // 打印add bus message
          })
        }
      }
      </script>
      
  4. Vuex

  5. $parent

    • 功能说明

      • 子组件可以该组件的父实例和组件
    • 目录结构

      components
         ├── Parent.vue
         ├── Child.vue
      
    • 代码结构

      Parent.vue 定义参数

      <template>
        <div>
          parent comp
          <Child />
        </div>
      </template>
      ​
      <script>
      import Child from './child'
      export default {
        data() {
          return {
            baz: 'baz'
          }
        },
        components: {
          Child
        },
      }
      </script>
      

      Child.vue 使用$parent获取参数

      <template>
        <div>
         child comp
        </div>
      </template>
      ​
      <script>
      export default {
        mounted () {
            console.log(this.$parent.baz); // baz
        }
      }
      </script>
      
  6. $children

    • 功能说明

      • 父组件可以该组件的子实例和组件,多个子组件的时候是无序的。
    • 目录结构

      components
         ├── Parent.vue
         ├── Child.vue
      
    • 代码结构

      Child.vue 定义参数

      <template>
        <div>
         child comp
        </div>
      </template>
      ​
      <script>
      export default {
        data() {
          return {
            bar: 'bar'
          }
        }
      }
      </script>
      

      Parent.vue 使用$children获取参数

      <template>
        <div>
          parent comp
          <Child />
        </div>
      </template>
      ​
      <script>
      import Child from './child'
      export default {
        mounted() {
          console.log(this.$children[0].bar) // bar
        },
        components: {
          Child
        },
      }
      </script>
      
  7. $root

    • 功能说明

      • 子组件可以访问该组件的根实例的属性和方法
    • 目录结构

      components
         ├── Root.vue
         ├── Child.vue
      
    • 代码结构

      Root.vue 定义参数

      <template>
        <div>
         root comp
         <Child />
        </div>
      </template>
      ​
      <script>
      import Child from './child'
      export default {
        data() {
          return {
            bar: 'bar'
          }
        },
        components: {
          Child
        },
      }
      </script>
      

      Child.vue 使用$root获取参数

      <template>
        <div>
          child comp
        </div>
      </template>
      ​
      <script>
      export default {
        mounted() {
          console.log(this.$root.bar) // bar
        },
      }
      </script>
      
  8. $refs

    • 功能说明

      • ref获取的是真实DOM元素,如果放到组件上就代表的是当前组件的实例。父组件中可以直接获取子组件的方法和数据。
    • 目录结构

      components
         ├── Parent.vue
         ├── Child.vue
      
    • 代码结构

      Child.vue 定义参数和方法

      <template>
        <div>
          child comp
          <button @click="add">child 点击</button>
        </div>
      </template>
      ​
      <script>
        import Goundson from './goundson'
        export default {
          data() {
            return {
              bar: ''
            }
          },
          methods: {
            add() {
              console.log('child func')
            },
          },
        }
      </script>
      

      Parent.vue 使用ref获取参数和方法

      <template>
        <div>
          parent comp
          <Child ref="child" />
        </div>
      </template>
      ​
      <script>
      import Child from './child'
      export default {
        mounted() {
          this.$refs.child.bar = 'barrrrrrr'
          this.$refs.child.add() // 打印child func
        },
        components: {
          Child
        },
      }
      </script>
      
  9. Provide/Inject

    • 功能说明

      • 隔代传参,允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件的层级有多深,并在其上下游关系成立的时间里始终生效。
      • 这个方法使用之后会使结构比较混乱一般在开发项目中是不会使用,作用于封装组件库。
    • 目录结构

      components
         ├── Parent.vue   // 父亲
         ├── Child.vue     // 儿子1
         ├── Goundson.vue  //孙子1
      
    • 代码结构

      Parent.vue 使用Provide注入数据

      <template>
        <div>
          parent comp
          <Child />
        </div>
      </template>
      ​
      <script>
      import Child from './child'
      export default {
        provide() {
          return {
            baz: 'baz'
          }
        },
        components: {
          Child
        },
      }
      </script>
      

      Child.vue 放入孙子组件

      <template>
        <div>
          child comp 
          <Goundson></Goundson>
        </div>
      </template>
      ​
      <script>
        import Goundson from './goundson'
        export default {
          components: {
            Goundson,
          },
        }
      </script>
      

      Goundson.vue 孙子组件使用inject 获取注入下来的数据

      <template>
        <div>
          goundson comp
          {{ baz }}
        </div>
      </template>
      ​
      <script>
        export default {
          inject: ['baz'],
        }
      </script>
      
  10. $attrs

    • 功能说明

      • 批量向下传入属性。一般不在props定义的属性,都会放在里面。
    • 目录结构

      components
         ├── Parent.vue   // 父亲
         ├── Child.vue    // 儿子
      
    • 代码结构

      Parent.vue 定义参数并传递给子组件

      <template>
        <div>
          parent comp
          <Child :foo="foo" />
        </div>
      </template>
      ​
      <script>
      import Child from './child'
      export default {
        data() {
          return {
            foo: 'foo'
          }
        },
        components: {
          Child
        },
      }
      </script>
      

      Child.vue 在不定义props时使用$attrs获取参数

      <template>
        <div>
          child comp
          {{ $attrs.foo }}
        </div>
      </template>
      ​
      <script>
        export default {}
      </script>
      
  11. $listeners

    • 功能说明

      • 批量向下传入方法,一般不在methods定义的属性,都会放在里面。
    • 目录结构

      components
         ├── Parent.vue   // 父亲
         ├── Child.vue    // 儿子
         ├── Goundson.vue    // 孙子
      
    • 代码结构

      Parent..vue 定义方法

      <template>
        <div>
          parent comp
          <Child @some-event="onSomeEvent" />
        </div>
      </template>
      ​
      <script>
      import Child from './child'
      export default {
        components: {
          Child
        },
      }
      </script>
      

      Child.vue 做展开

      <template>
        <div>
          child comp
          <Goundson v-on="$listeners"></Goundson>
        </div>
      </template>
      ​
      <script>
        import Goundson from './goundson'
        export default {
          components: {
            Goundson,
          },
        }
      </script>
      

      Goundson.vue 触发方法

      <template>
        <div>
          goundson comp
          <button @click="$emit('some-event', 'some event message')">点击</button>
        </div>
      </template>
      ​
      <script>
        export default {}
      </script>
      

结语

以上就是全部内容,大部分的通讯方式多用于组件库开发中,欢迎评论指点,一起交流一起进步 🙏🙏🙏🙏。