Github
抽空梳理了一下 Vue 罕用的组件之间的通信形式,而后想通过应用的技术进行分类整理笔记。
Prop 传值
应用范畴
父组件向子组件传值。
应用办法
父组件
<template>
<div id="app">
<div class="app">
<div class="title">App.vue</div>
</div>
<!-- 将 text1 绑定给 Component1 -->
<component1 :text="text1" />
</div>
</template>
export default {
name: 'App',
components: {Component1,},
data(){
return{text1:"Text From App.vue",}
}
}
</script>
子组件
<template>
<div class="component1">
<div class="title">Component1</div>
<div>
<!-- 将父组件传递过去的 text 进行展现 -->
<span class="text-bold">text:</span>
{{text}}
</div>
</div>
</template>
<script>
export default {
name: "Component1",
// 通过 props 来接管 text
props:{
text:{type:String}
},
}
</script>
成果展现
留神
父组件通过 Prop 传值给子组件是属于单向数据流,因而当父组件批改该值的时候,子组件也会随之更新数据;而子组件是不应该在外部扭转 prop 的。如果你能够这么做,然而 Vue 不举荐此做法,并会在控制台收回正告。
v-on 事件绑定
应用范畴
子组件调用父组件办法。
应用办法
父组件
<template>
<div id="app">
<div class="app">
<div class="title">App.vue</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
</div>
<!-- 将事件 addCount 绑定给 Component1 -->
<component1 @addCount="addCount" />
</div>
</template>
<script>
import Component1 from "@/components/Component1";
export default {
name: 'App',
components: {Component1},
data(){
return{count:0}
},
methods:{addCount(){this.count++;}
}
}
</script>
子组件
<template>
<div class="component1">
<div class="title">Component1</div>
<!-- Component1 的 button 触发 addParentCount -->
<button @click="addParentCount">
add count of App.vue
</button>
</div>
</template>
<script>
export default {
name: "Component1",
methods:{
// 调用组件绑定的 addCount 办法
addParentCount(){this.$emit('addCount')
}
}
}
</script>
成果展现
留神
this.$emit()
的第一个参数为事件绑定的 EventName,而从第二个参数开始为函数的参数,能够传多个参数值,意味着能够通过此办法从子组件传值给父组件。
ref 组件注册
适用范围
父组件获取子组件的值或调用子组件的办法。
应用办法
父组件
<template>
<div id="app">
<div class="app">
<div class="title">App.vue</div>
<!-- 显示获取到的子组件的 text -->
<div>
<span class="text-bold">text:</span>
{{text2}}
</div>
<!-- 减少子组件的 count 值 -->
<button @click="ChildrenCount">
add count of Component1.vue
</button>
</div>
<!-- 进行组件注册 -->
<component1 ref="component1" />
</div>
</template>
<script>
import Component1 from "@/components/Component1";
export default {
name: 'App',
components: {Component1,},
data(){
return{text2:''}
},
mounted() {
// 获取子组件的 text1 值
this.text2 = this.$refs.component1.text1 || '';
},
methods:{
// 调用子组件的办法
ChildrenCount(){this.$refs.component1.addCount();
}
}
}
</script>
子组件
<template>
<div class="component1">
<div class="title">Component1</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
</div>
</template>
<script>
export default {
name: "Component1",
data(){
return{
// 父组件获取到此值
text1: 'Text From Component1.vue',
count: 0
}
},
methods:{
// 父组件调用此办法
addCount(){this.count++;}
}
}
</script>
成果
留神
this.$refs
是组件渲染后才会进行填充,因而无奈在计算属性 computed
应用,打印进去会显示 undefined
。
EventBus 事件总线
应用范畴
任意组件间的事件调用。
应用办法
初始化 EventBus
共有两种形式能够初始化 EventBus,第一种形式是新建一个 eventBus.js
,内容如下:
import Vue from 'vue'
export const EventBus = new Vue()
而后应用时均在两个组件内引入该文件。
import {EventBus} from "../eventBus.js";
而第二种形式是全局注册 EventBus。
在我的项目的 main.js
文件下,插入注册代码:
Vue.prototype.$EventBus = new Vue()
而后应用时即可通过 this.$EventBus
调用。
前面的案例均用第二种办法实现。
第一个组件
<template>
<div class="component2">
<div class="title">Component2</div>
<!-- 获取 input 值更新另一个组件的 count 值 -->
<div>
<input type="number" placeholder="Number..." v-model="value">
</div>
<!-- 点击 button 触发事件 -->
<button @click="changeComponent1Count">
change count of Component1
</button>
</div>
</template>
<script>
export default {
name: "Component2",
data() {
return {value:''}
},
methods:{
// 在 EventBus 总线注册 changeCount 事件,并将 value 值传过来
changeComponent1Count(){this.$EventBus.$emit("changeCount",this.value)
}
}
}
</script>
第二个组件
<template>
<div class="component1">
<div class="title">Component1</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
</div>
</template>
<script>
export default {
name: "Component1",
data(){
return{count: 0}
},
// 在 mounted 中监听 EventBus 接管 changeCount 事件,并触发回调函数将 value 值赋给 count
mounted(){this.$EventBus.$on('changeCount',(value)=> this.count = value);
}
}
</script>
成果
留神
尽管在 Vue 中能够应用 EventBus
来作为沟通桥梁的概念,就像是所有组件共用雷同的事件核心,能够向该核心注册发送事件或接管事件,使得所有组件都能够高低平行地告诉其余组件,然而若应用不慎,就会造成难以保护的“劫难”。
Vue 是单页利用,如果你在某一个页面刷新了之后,与之相干的 EventBus
会被移除,这样就导致业务走不上来。还要就是如果业务有重复操作的页面,EventBus
在监听的时候就会触发很屡次,也是一个十分大的隐患。这时候咱们就须要好好解决 EventBus
在我的项目中的关系。通常会用到,在 vue 页面销毁时,同时移除 EventBus
事件监听。
移除 EventBus
事件监听的办法如下:
// 移除指定事件
this.$EventBus.$off('changeCount')
// 移除所有事件
this.$EventBus.$off()
$parent 与 $children
应用范畴
通过插槽嵌套的父子组件进行事件调用和传值。
应用办法
App.vue
<template>
<div id="app">
<component3>
<component4></component4>
</component3>
</div>
</template>
<script>
import Component3 from "@/components/Component3";
import Component4 from "@/components/Component4";
export default {
name: 'App',
components: {
Component3,
Component4,
}
}
</script>
父组件
<template>
<div class="component3">
<div class="title">Component3</div>
<!-- 获取到子组件的 text1 值 -->
<div>
<span class="text-bold">text:</span>
{{text2}}
</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
<!-- 减少子组件的 count 值 -->
<button @click="addChildrenCount">
add count of Component4.vue
</button>
<!-- 插槽 -->
<slot></slot>
</div>
</template>
<script>
export default {
name: "Component3",
data() {
return {
text1: 'Text From Component3.vue',
text2:'',
count: 0
}
},
mounted() {
// 获取子组件的 text1 值
this.text2 = this.$children[0].text1;
// 监听子组件调用 changeCount,并将参数 value 赋值给父组件的 count
this.$on("changeCount",value => this.count = value);
},
methods:{addChildrenCount(){
// 调用第一个子组件绑定的 addCount 办法
this.$children[0].$emit('addCount');
}
}
}
</script>
子组件
<template>
<div class="component4">
<div class="title">Component4</div>
<!-- 获取到父组件的 text1 值 -->
<div>
<span class="text-bold">text:</span>
{{text2}}
</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
<div>
<input type="number" placeholder="Number..." v-model="value">
</div>
<!-- 批改父组件的 count 值 -->
<button @click="changeParentCount">
change count of Component3.vue
</button>
</div>
</template>
<script>
export default {
name: "Component4",
data() {
return {
text1: 'Text From Component4.vue',
text2:'',
count: 0,
value:''
}
},
mounted() {
// 获取父组件的 text1 值
this.text2 = this.$parent.text1;
// 监听父组件调用 addCount,并将 count++
this.$on('addCount',() => this.count++);
},
methods:{changeParentCount(){
// 调用父组件绑定的 changeCount 办法,并传入 value 参数
this.$parent.$emit('changeCount',this.value)
},
}
}
</script>
成果
留神
同 $refs
,$parent
和 $children
是组件渲染后才会进行填充,因而无奈在计算属性 computed
应用。
$children
返回的是一个数组,一个父组件可能有多个子组件,但一个子组件只能有一个父组件。
provide 与 inject
应用范畴
父组件向任一后辈组件传值和办法,实用于失常嵌套和插槽嵌套。
应用办法
App.vue
<template>
<div id="app">
<component3>
<component4>
<component5></component5>
</component4>
</component3>
</div>
</template>
<script>
import Component3 from "@/components/Component3";
import Component4 from "@/components/Component4";
import Component5 from "@/components/Component5";
export default {
name: 'App',
components: {
Component3,
Component4,
Component5,
},
}
</script>
父组件
<template>
<div class="component3">
<div class="title">Component3</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
<!-- 插槽 -->
<slot></slot>
</div>
</template>
<script>
export default {
name: "Component3",
// 向后辈组件提供 text 和执行上下文 this
provide(){
return{
text:this.text1,
component3:this
}
},
methods:{addCount(){this.count++;}
}
}
</script>
子组件
<template>
<div class="component4">
<div class="title">Component4</div>、<!-- 显示父组件的 text 值 -->
<div>
<span class="text-bold">text:</span>
{{text}}
</div>
<slot></slot>
</div>
</template>
<script>
export default {
name: "Component4",
// 接管父组件的 text 值
inject:['text']
}
</script>
孙组件
<template>
<div class="component5">
<div class="title">Component5</div>
<!-- 显示祖组件的 text 值 -->
<div>
<span class="text-bold">text:</span>
{{text}}
</div>
<!-- 减少祖组件的 count 值 -->
<button @click="addGrandParentCount">
add count of Component3.vue
</button>
</div>
</template>
<script>
export default {
name: "Component5",
// 接管祖组件的 text 值和执行上下文
inject:['text','component3'],
methods:{
// 通过祖组件执行上下文调用其办法
addGrandParentCount(){this.component3.addCount();
}
}
}
</script>
成果
$attrs 与 $listeners
应用范畴
孙组件获取祖组件的值或调用祖组件事件。
应用办法
祖组件
<template>
<div class="component6">
<div class="title">Component6</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
<!-- 祖组件向本人组件传递了 text1 与 text2 和一个 addCount 事件 -->
<component7 :text1="text" :text2="text" @addCount="addCount" />
</div>
</template>
<script>
import Component7 from "@/components/Component7";
export default {
name: "Component6",
components:{Component7},
data() {
return {
text: 'Text From Component6.vue',
count: 0
}
},
methods:{addCount(){this.count ++}
}
}
</script>
父组件
<template>
<div class="component7">
<div class="title">Component7</div>
<div>
<span class="text-bold">text:</span>
{{text1}}
</div>
<!-- 将不被父组件 prop 辨认的 attribute 绑定到孙组件,也将祖组件的事件绑定到孙组件 -->
<component8 v-bind="$attrs" v-on="$listeners" />
</div>
</template>
<script>
import Component8 from "@/components/Component8";
export default {
name: "Component7",
// 父组件 prop 辨认了 text1,因而 text1 不会传递到孙组件
props:{
text1:{type:String}
},
components:{Component8}
}
</script>
孙组件
<template>
<div class="component8">
<div class="title">Component8</div>
<div>
<span class="text-bold">text:</span>
{{text2}}
</div>
<button @click="addGrandparentCount">
add count of Component6.vue
</button>
</div>
</template>
<script>
export default {
name: "Component8",
// 孙组件获取到祖组件的 text2
props:{
text2:{type:String},
},
methods:{
// 孙组件调用了祖组件的 addCount 事件
addGrandparentCount(){this.$emit('addCount');
}
}
}
</script>
成果
留神
$attrs
蕴含了父作用域中不作为 prop 被辨认 (且获取) 的 attribute 绑定 (class 和 style 除外)。因而当 text1
已被子组件 prop 获取后,在孙组件是获取不到 text1
的。