跳到主要内容

三、组件通信

01 - props(父子)

父组件<Children name="jack" age=18 />

子组件:三种接收方式

  1. props: ['name','age'],
  2. props: {name: String, age: Number}
  3. props: {name: {type: String, required: true}, age: {type: Number, default: 18}}

props只能是父组件向子组件进行传值,props使得父子组件之间形成了一个单向下行绑定。子组件的数据会随着父组件不断更新。

props 可以显示定义一个或一个以上的数据,对于接收的数据,可以是各种数据类型,同样也可以传递一个函数。

02 - provide inject(父子)

这种方式就是Vue中的依赖注入,该方法用于父子组件之间的通信。当然这里所说的父子不一定是真正的父子,也可以是祖孙组件,在层数很深的情况下,可以使用这种方法来进行传值。就不用一层一层的传递了。

provide / inject是Vue提供的两个钩子,和data、methods是同级的。并且provide的书写形式和data一样。

provide 钩子用来发送数据或方法

inject钩子用来接收数据或方法

03 - $emit(父子)

自定义事件($emit)

04 - ref $refs(父子)

应用在 html 标签上获取的是真实 DOM 元素,应用在组件标签上是组件实例对象(vc)。可以通过实例来访问组件的数据和方法。

使用方式

打标识:<h1 ref="xxx"> ... </h1>或<School ref="xxx"></School>

获取:this.$refs.xxx

05 - $parent $children

使用$parent可以让组件访问父组件的实例(访问的是上一级父组件的属性和方法)【对象】 使用$children可以让组件访问子组件的实例,但是,$children并不能保证顺序(如果有多个孩子,不要用索引的方式,可以用$refs打标记),并且访问的数据也不是响应式的。【数组】

  • 父组件

    • ref可以获取到某一个DOM节点、组件标签、子组件标签(以便操作子组件的数据与方法);$children组件实例的属性,可以获取到当前组件的全部子组件【数组】
  • 子组件

    • $parent组件实例的属性,可以获取到当前子组件的父组件。从而可以操作父组件的数据和方法
  • 跨代通信

    考虑一种场景,如果A是B组件的父组件,B是C组件的父组件。如果想要组件A给组件C传递数据,这种隔代的数据,该使用哪种方式呢?

如果是用props/$emit来一级一级的传递,确实可以完成,但是比较复杂;如果使用事件总线,在多人开发或者项目较大的时候,维护起来很麻烦;如果使用Vuex,的确也可以,但是如果仅仅是传递数据,那可能就有点浪费了。

针对上述情况,Vue引入了$attrs / $listeners,实现组件之间的跨代通信。

06 - $attrs $listeners

  • $attrs:继承所有的父组件属性(除了子组件prop接收的属性),一般用在子组件的子元素上【对象形式】

  • $listeners:该属性是一个对象,里面包含了作用在这个组件上的所有监听器,可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。(相当于子组件继承父组件的事件)【对象形式】

  • inheritAttrs

    • inheritAttrs:默认值 true,继承所有的父组件属性(除 props 的特定绑定)作为普通的HTML特性应用在子组件的根元素上,如果你不希望组件的根元素继承特性设置 inheritAttrs: false ,但是 class 属性会继承。
  • 注意

    • 孙子组件中能直接触发父组件的自定义方法的原因在于子组件调用孙子组件时 使用 v-on 绑定了$listeners 属性
    • 在子组件中通过v-bind 绑定$attrs属性,孙子组件可以直接获取到父组件中传递下来的props(除了子组件中props声明的)

07 - 全局事件总线(任意)

new Vue({
render: h => h(App),
beforeCreate() {
// 安装全局事件总线,$bus就是当前应用的vm
Vue.prototype.$bus = this
},
}).$mount('#app')

接收数据:A组件想接收数据,则在A组件中给 $bus 绑定自定义事件,事件的回调留在A组件自身。


<script>
export default {
methods: {
demo() {
}
},
mounted() {
// 两种方式都可以
// this.$bus.$on("hello", (data) => {});
this.$bus.$on('hello', this.demo)
},
beforeDestroy() {
// 解绑事件
this.$bus.$off("hello");
},
};
</script>

提供数据this.$bus.$emit('xxx',数据)

最好在 beforeDestroy 钩子中,用 $off 去解绑当前组件所用到的事件。

08 - vuex(任意)

核心概念:state mutations actions getters modules

09 - slot(父子)

10 - pubsub-js(任意)

在vue中几乎不用,一般用于React。

  1. 安装 pubsubnpm i pubsub-js

  2. 引入: import pubsub from 'pubsub-js'

  3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

    methods(){
    demo(data){......}
    }
    ......
    mounted() {
    this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
    }
  4. 提供数据:pubsub.publish('xxx',数据)

  5. 最好在 beforeDestroy 钩子中,用PubSub.unsubscribe(pid)去取消订阅。