组件通信常⽤⽅式:
- props
- eventBus
- vuex
⾃定义事件:
- 边界情况
- $parent
- $children
- $root
- $refs
- provide/inject
- ⾮prop特性
// parent
<a name="vjtBr"></a>### props的形式```javascriptprops: {// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)propA: Number,// 多个可能的类型propB: [String, Number],// 必填的字符串propC: {type: String,required: true},// 带有默认值的数字propD: {type: Number,default: 100},// 带有默认值的对象propE: {type: Object,// 对象或数组默认值必须从一个工厂函数获取default: function () {return { message: 'hello' }}},// 自定义验证函数propF: {validator: function (value) {// 这个值必须匹配下列字符串中的一个return ['success', 'warning', 'danger'].indexOf(value) !== -1}}}
type 可以是下列原生构造函数中的一个:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
可以通过父给子传值方法,使子组件可以访问父组件的方法和作用域
2. 自定义事件
子给父传值
// childthis.$emit('add', good)// parent<child @add="handleAdd"></child>
3. $parent/$root/$children
$parent
兄弟组件之间通信可通过共同祖辈搭桥,
// brother1this.$parent.$on('foo', handle)// brother2this.$parent.$emit('foo')
$root
访问vue根实例
$children
父组件可以通过$children访问子组件实现父子通信。
// parentthis.$children[0].xx = 'xxx'
注意:$children不能保证⼦元素顺序 和$refs有什么区别? refs可以引用组件也可以引用原生
4. $attrs/$listeners
包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 ( class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外),并且可以通过v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用
// child:并未在props中声明foo<p>{{$attrs.foo}}</p>// parent<HelloWorld foo="foo"/>
- $attrs:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件。当一个组件没有声明任何 props 时,它包含所有父作用域的绑定 (class 和 style 除外)。
$listeners:包含了父作用域中的 (不含 .native 修饰符) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件。它是一个对象,里面包含了作用在这个组件上的所有事件监听器,相当于子组件继承了父组件的事件。
5. refs
访问子组件实例或子元素,也可以访问html元素
// parent<HelloWorld ref="hw"/>mounted() {this.$refs.hw.xx = 'xxx'}
6. provide/inject
能够实现祖先和后代之间传值
// 父级组件提供 'foo'var Provider = {provide: {foo: 'bar'},// ...}// 子组件注入 'foo'var Child = {inject: ['foo'],created () {console.log(this.foo) // => "bar"}// ...}
provide和 inject主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。 提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个响应式的对象(data里的),那么其对象的 property 还是可响应的
7. 事件总线
任意两个组件之间传值常用事件总线
// 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))}}}// main.jsVue.prototype.$bus = new Bus()// child1this.$bus.$on('foo', handle)// child2this.$bus.$emit('foo')
实践中通常用Vue代替Bus,因为Vue已经实现了相应接口
两种实现方式
// 1.eventBus.jsimport Vue from 'vue'export const EventBus = new Vue()// 2.main.jsVue.prototype.$EventBus = new Vue()
- 触发事件
$emit('event',args) - 监听事件
$on('event',()=>{..}) - 移除事件
$off('event')8. Vuex
创建唯一的全局数据管理者store,通过它管理数据并通知组件状态变更。
二 插槽
插槽语法是Vue 实现的内容分发 API,用于复合组件开发。该技术在通用组件库开发中有大量应用。
1. 匿名插槽
// comp1<div><slot></slot></div>// parent<comp>hello</comp>
2. 具名插槽
将内容分发到子组件指定位置
// comp2<div><slot></slot><slot name="content"></slot></div>// parent<Comp2><!-- 默认插槽用default做参数 --><template v-slot:default>具名插槽</template><!-- 具名插槽用插槽名做参数 --><template v-slot:content>内容...</template></Comp2>
3. 作用域插槽
分发内容要用到子组件中的数据
// comp3<div><slot :foo="foo"></slot></div>// parent<Comp3><!-- 把v-slot的值指定为作用域上下文对象 --><template v-slot:default="slotProps"> 来自子组件数据:{{slotProps.foo}} </template></Comp3>// default可以省略,具名插槽时为具名插槽的名字
