1.1 Props
components
├── Parent.vue // 父
└── Son1.vue // 子1
父组件中使用子组件。
// Parent.vue
父组件: {{num}}
子组件通过 props
接收父组件数据。
// Son1.vue
子组件1: {{parentNum}}
1.2 $emit 使用
components
├── Parent.vue // 父
└── Son1.vue // 子1
父组件通过 v-on
将事件绑定在子组件身上。
// Parent.vue
父组件: {{num}}
子组件通过 $emit
触发父组件绑定在自己身上的事件,调用父组件相应方法,由父组件自行修改数据(遵循单向数据流)。
// Son1.vue
子组件1: {{parentNum}}
1.2.1 .sync 语法糖
改写:对以上绑定事件方法进行改写。
父组件向子组件传递值与方法,此时绑定的事件为 changeNum:xxx
。
// Parent.vue
父组件: {{num}}
同样,子组件触发自身 changeNum:xxx
事件,调用父组件方法修改数据。
// Son1.vue
子组件1: {{parentNum}}
进一步改写:将事件 changeNum:xxx
改写为 update:parentNum
。
// Parent.vue
父组件: {{num}}
同理,子组件调用方法改为 update:parentNum
。
// Son1.vue
子组件1: {{parentNum}}
语法糖 .sync
诞生:同步父子组件数据。
父组件使用 :parentNum.sync="num"
语法糖简写,省略 @update:parentNum="change"
。
因为语法糖
:parentNum.sync="num"
是
:parentNum="num" @update:parentNum="change"
即
:parentNum="num" @update:parentNum="newNum => num = newNum"
的简写,已经包含数据修改方法
newNum => num = newNum
,故不再需要change
事件。
// Parent.vue
父组件: {{num}}
子组件同上改进,触发 update:parentNum
事件,调用父组件方法修改数据。
注意,使用语法糖
.sync
时,子组件必须使用update
。
// Son1.vue
子组件1: {{parentNum}}
1.2.2 v-model 语法糖
同上改写,此时 父组件传值绑定为 value
,方法修改为 input
。
// Parent.vue
父组件: {{num}}
此时子组件值使用 value
,触发方法使用 input
。
子组件1: {{value}}
语法糖 v-model
诞生。
父组件使用 v-model="num"
语法糖简写,省略 :value="num" @input="change"
。
因为语法糖
v-model="num"
是
:value="num" @input="change"
即
:value="num" @input="newNum => num = newNum"
的简写,已经包含数据修改方法
newNum => num = newNum
,故不再需要change
事件。
// Parent.vue
父组件: {{num}}
同上,子组件接收属性名只能是 value
,触发回调事件名只能是input
。
// Son1.vue
子组件1: {{value}}
1.3 children
components
├── Parent.vue // 父
├── Son1.vue // 子1
└── GrandSon.vue // 孙1
父组件数据传递到子组件,将事件 changeNum
绑定到子组件上。
// Parent.vue
父组件: {{num}}
子组件接收数据,并将数据传递到孙组件。
// Son1.vue
子组件1: {{parentNum}}
孙组件接收数据,并通过 $parent
调用其父组件(即子组件),由于子组件上绑定有爷组件(即父组件)传递的方法 changeNum
,故可进行调用修改数据。
// Grandson1.vue
孙组件1:{{parentNum}}
1.3.1 $dispatch 向上派发
如上,如果层级很深,那么就会出现 $parent.$parent.....
的情况,可以封装一个 $dispatch
方法向上进行派发。
在 main.js
中 为 Vue
原型添加 $dispatch
方法,以便每个 vue
实例均可使用。
// main.js
import Vue from 'vue'
import App from './App.vue'
// 向上派发
Vue.prototype.$dispatch = function (eventName, value) {
let parent = this.$parent
while (parent) {
parent.$emit(eventName, value)
parent = parent.$parent
}
}
new Vue({
render: h => h(App)
}).$mount('#app')
后代组件调用原型上的 $dispatch
方法。
// Grandson1.vue
孙组件1:{{parentNum}}
1.3.2 $broadcast 向下通知
同理,如果层级很深,调用后代方法就会出现多个 $children
循环遍历的情况,可以封装一个 $broadcast
方法向下进行通知。
在 main.js
中 为 Vue
原型添加 $dispatch
方法,以便每个 vue
实例均可使用。
// main.js
import Vue from 'vue'
import App from './App.vue'
// 向下通知
Vue.prototype.$broadcast = function (eventName, value) {
const broadcast = children => {
children.forEach(child => {
child.$emit(eventName, value)
if (child.$children) broadcast(child.$children)
})
}
broadcast(this.$children)
}
new Vue({
render: h => h(App)
}).$mount('#app')
为长辈组件添加调用后代组件方法的方法。
// Parent.vue
父组件: {{num}}
在后代组件中绑定供长辈组件调用的方法。
// Son1.vue
子组件1: {{parentNum}}
1.4 listeners
components
├── Parent.vue // 父
├── Son1.vue // 子1
└── GrandSon.vue // 孙1
1.4.1 $attrrs 属性集合
父组件定义多个属性,传递给孙组件。
需先由父组件传递给子组件。
父组件
子组件可以使用 props
依次接收,然后在传递给孙组件。但是,每个组件向下传递时都写在 props
中很麻烦,所以,可以使用 $attrs
统一接收,并传递给后代组件传递。
接收的
$attrs
是属性对象,可以传递单个属性,也可使用v-bind="{name: $attrs.name, age: '$attrs.age'}"
传递部分属性,也可以使用v-bind="$attrs"
传递全部属性。
子组件1: {{$attrs}}
孙组件使用父组件传递的属性。
//Grandson1.vue
孙组件1:姓名:{{$attrs.name}} 年龄:{{$attrs.age}} 性别:{{$attrs.sex}}
此时可以看到,传递的属性同样添加到了 DOM
属性上。
若不想将属性添加到 DOM
上,可声明不继承。
//Grandson1.vue
孙组件1:姓名:{{$attrs.name}} 年龄:{{$attrs.age}} 性别:{{$attrs.sex}}
1.4.2 $listeners 方法集合
父组件定义多个属性,传递给孙组件。
需先由父组件传递给子组件。
// Parent.vue
父组件 {{num}}
子组件使用 $listener
接收父组件传入的全部方法,并使用 v-on
传递给孙组件。
// Son1.vue
子组件1
孙组件调用 $listeners
中的某个方法。
// Grandson1.vue
孙组件1:
1.5 provide inject
如上,后代使用前辈方法需要依次传递,但希望能够实现前辈组件定义方法,后代均可直接共享(类似于 react
中的 context
)。
后代组件可以注入数据,也可以注入前辈组件(前辈组件先提供)。
components
├── Parent.vue // 父
├── Son1.vue // 子1
└── GrandSon.vue // 孙1
1.5.1 Provide
父组件使用 provide
提供自身。
// Parent.vue
父组件 {{num}}
1.5.2 inject
孙组件使用 inject
注入其爷组件(父组件)。
// Grandson1.vue
孙组件1:
1.6 ref
ref
放在 DOM
元素上,获取的是 DOM
节点。放在组件上,获取的是当前组件。故可以使用 ref
调用子组件属性与方法。
components
├── Parent.vue // 父
└── Son1.vue // 子1
子组件定义属性与方法。
// Son1.vue
子组件1:{{num}}
父组件调用子组件属性与方法。
// Parent.vue
父组件 {{num}}
1.7 EventBus
components
├── Parent.vue // 父
├── Son1.vue // 子1
├── Grandson1.vue // 子1
└── Son2.vue // 子2
EventBus
通常用于兄弟组件及其他非间隔组件之间的数据通信。
在 main.js
中在 Vue
原型上添加 $bus
,其是一个 vue
实例。
为什么使用
vue
实例?因为vue
实例上有$on
和$emit
方法,可用于收集和触发事件。
import Vue from 'vue'
import App from './App.vue'
Vue.prototype.$bus = new Vue()
new Vue({
render: h => h(App)
}).$mount('#app')
父组件引入两个子组件。
// Parent.vue
父组件
子组件1在 $bus
上绑定事件。
// Son1.vue
子组件1
子组件2在 $bus
上绑定事件。
// Son2.vue
子组件2
孙组件1触发 $bus
上绑定的指定事件。
![8](../../8.gif
孙组件1:
如上,此 EventBus
方法缺陷是如果绑定了相同的事件名,在一次触发时所有相同事件名事件都将被触发。
1.8 Vuex
待添加。