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
的。