回顾Vue组件通信的7种方式
前言
下周准备开始投简历了,这2天把vue相关的知识做一下整理,也算是一个复习了。主要涉及到vue双向绑定原理,组件通讯方式,自定义指令等等,有错误或者不足,后期再修改文章予以修正和补充。
一、Props & $emit()
父组件通过props想子组件传递数据,子组件通过$emit来触发父组件的监听事件,来抛出数据让父组件在事件处理函数中接收。
父组件:
<template>
<div class="parent">
<h1 id="parent">父组件</h1>
<p>{{msg}}</p>
<!-- 在页面上使用子组件(单标签使用) 绑定自定义属性msg,自定义事件changeMsg ,然后将$event赋值给msg -->
<c1 :msg="msg" @changeMsg="msg = $event" />
</div>
</template>
<script>
//引入子组件 然后在components中进行注册
import c1 from "@/components/c1.vue";
export default {
components: {
c1,
},
data() {
return {
msg:'这是第一种通信方式。'
};
}
};
</script>
<style lang='less' scoped>
</style>
子组件:
<template>
<div>
<h1>子组件</h1>
<p>{{msg}}</p>
<button @click="handleClick">按钮1</button>
</div>
</template>
<script>
export default {
name: "c1",
//在props中使用父组件传过来的msg
props: ["msg"],
data() {
return {};
},
methods: {
handleClick() {
//通过$emit触发父组件的自定义事件,并将bye-bye传递,父组件通过$event接收
this.$emit("changeMsg", "bye-bye");
},
}
};
</script>
<style lang='less' scoped>
</style>
二、callback
使用回调函数来实现组件通信
父组件:
<template>
<div class="parent">
<h1 id="parent">父组件</h1>
<p>{{msg}}</p>
<!-- 绑定自定义属性msg,changeMsg ,然后再methods中定义回调函数修改msg,将回调函数作为自定义属性传递给子组件 -->
<c2 :msg="msg" :changeMsgFn="changeMsg" />
</div>
</template>
<script>
//引入子组件 然后在components中进行注册
import c2 from "@/components/c2.vue";
export default {
components: {
c2,
},
data() {
return {
msg: "这是第二种通信方式。",
};
},
methods: {
changeMsg() {
this.msg = "bye-bye";
},
},
};
</script>
<style lang='less' scoped>
</style>
子组件:
<template>
<div>
<h1>子组件</h1>
<p>{{msg}}</p>
<button @click="changeMsgFn">按钮2</button>
</div>
</template>
<script>
export default {
name: "c2",
//在props中使用父组件传过来的msg,changeMsgFn
props: ["msg","changeMsgFn"]
};
</script>
<style lang='less' scoped>
</style>
三、$parent & $children
父组件:
<template>
<div class="parent">
<h1 id="parent">父组件</h1>
<p>{{msg}}</p>
<button @click="changeChildNumber">父按钮</button>
<c3 />
</div>
</template>
<script>
//引入子组件 然后在components中进行注册
import c3 from "@/components/c3.vue";
export default {
components: {
c3,
},
data() {
return {
msg: "这是第三种通信方式。",
};
},
methods: {
changeChildNumber() {
// 通过vue实例上的$children[0].number(可能有多个子组件,这里只有一个,所以取第0项)来获取子组件data中的number并将其改变值为666
this.$children[0].number = 666;
},
},
};
</script>
<style lang='less' scoped>
</style>
子组件:
<template>
<div>
<h1>子组件</h1>
<p>{{msg}}</p>
<p>{{number}}</p>
</div>
</template>
<script>
export default {
name: "c3",
data() {
return {
number: 0,
};
},
computed: {
//示例 通过计算属性 在子组件中显示父组件的msg的值
msg() {
return this.$parent.msg;
},
},
};
</script>
<style lang='less' scoped>
</style>
四、provide & inject
父组件通过provide来提供变量,子组件通过inject来注入变量。
父组件:
<template>
<div class="parent">
<h1 id="parent">父组件</h1>
<c4 />
</div>
</template>
<script>
//引入子组件 然后在components中进行注册
import c4 from "@/components/c4.vue";
export default {
components: {
c4,
},
// 通过provide提供一个变量
provide: {
msg: "这是第四种通信方式。",
},
};
</script>
<style lang='less' scoped>
</style>
子组件:
<template>
<div>
<h1>子组件</h1>
<!-- 消费之后也可以在子组件中进行使用了 -->
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
name: "c4",
//在inject进行消费
inject: ["msg"],
};
</script>
<style lang='less' scoped>
</style>
五、$attrs & $listeners
如果组件多层嵌套,孙组件甚至曾孙组件想和父组件通信,不可能使用props一级级传递,所以Vue2.4开始提供了
a
t
t
r
s
和
attrs和
attrs和listeners来解决这个问题。
父组件:
<template>
<div class="parent">
<h1 id="parent">父组件</h1>
<p>N:{{name}}</p>
<p>A:{{age}}</p>
<c5 :name="name" :age="age" @changeName="changeNameToAlex" />
</div>
</template>
<script>
//引入子组件 然后在components中进行注册
import c5 from "@/components/c5.vue";
export default {
components: {
c5,
},
data() {
return {
name: "Gary",
age: "27",
};
},
methods: {
changeNameToAlex() {
this.name = 'Alex'
},
},
};
</script>
<style lang='less' scoped>
</style>
子组件:
<template>
<div>
<h1>子组件</h1>
<!-- 通过$listener可以获取到父组件的事件监听器(也就是父组件中写在子组件上的自定义事件),从而去执行绑定的对应的事件处理函数changeNameToAlex -->
<button @click="$listeners.changeName">按钮5</button>
<!-- $attrs包括了从父组件传递过来的name age自定义属性 -->
<gc5 v-bind="$attrs" />
</div>
</template>
<script>
import gc5 from "./gc5";
export default {
name: "c5",
components: {
gc5,
},
};
</script>
<style lang='less' scoped>
</style>
孙组件:
<template>
<div>
<h1>孙组件</h1>
<!-- 孙组件中可以直接通过$attrs来访问这2个属性 -->
<p>n:{{$attrs.name}}</p>
<p>a:{{$attrs.age}}</p>
</div>
</template>
<script>
export default {
name: "gc5",
};
</script>
<style lang='less' scoped>
</style>
六、ref & $refs
父组件:
<template>
<div class="parent">
<h1 id="parent">父组件</h1>
<button @click="changeNameF">按钮6</button>
<!-- 这里可以理解为组件实例注册一个名字 -->
<c6 ref="child6Comp" />
</div>
</template>
<script>
//引入子组件 然后在components中进行注册
import c6 from "@/components/c6.vue";
export default {
components: {
c6,
},
methods: {
changeNameF() {
// 通过$refs.实例名字,可以获取到对应的组件实例,然后就可以访问该实例的属性和方法
console.log("点击前", this.$refs.child6Comp.name);
this.$refs.child6Comp.changeNameC();
console.log("点击后", this.$refs.child6Comp.name);
},
},
};
</script>
<style lang='less' scoped>
</style>
子组件:
<template>
<div>
<h1>子组件</h1>
<p>n:{{name}}</p>
</div>
</template>
<script>
export default {
name: "c6",
data() {
return {
name: "Gary",
};
},
methods: {
changeNameC() {
this.name = "Alex";
},
},
};
</script>
<style lang='less' scoped>
</style>
七、中央事件总线bus
BUS中央事件总线这种方便兄弟组件间通信的方式。
所谓BUS,就是创建一个Vue事件BUS对象,然后通过bus.$emit触发事件,然后通过bus.$on监听触发的事件这样来传递数据。
但实际上项目中我们可以使用vuex来实现这个功能。
看个例子:
创建一个utils下的bus.js
import Vue from 'vue'
const bus = new Vue()
export default bus
父组件:
<template>
<div class="parent">
<h1 id="parent">父组件</h1>
<b1 />
<b2 />
</div>
</template>
<script>
//引入子组件 然后在components中进行注册
import b1 from "@/components/b1.vue";
import b2 from "@/components/b2.vue";
export default {
components: {
b1,
b2,
},
};
</script>
<style lang='less' scoped>
</style>
兄弟组件1:
<template>
<div>
<h1>兄弟组件1</h1>
<p>{{msg}}</p>
<p>小弟传递过来的数据:{{b2Msg}}</p>
</div>
</template>
<script>
import bus from '../../utils/bus'
export default {
name: "b1",
components: {},
data() {
return {
msg: "我是大哥。",
b2Msg: "还没说话",
};
},
mounted() {
// 通过$on去绑定全局事件 busEvent 注意是全局事件!
bus.$on("busEvent", (val) => {
this.b2Msg = val;
});
},
};
</script>
<style lang='less' scoped>
</style>
兄弟组件2:
<template>
<div>
<h1>兄弟组件2</h1>
<p>{{msg}}</p>
<!-- 点击按钮 触发passData -->
<button @click="passData('大哥是我!')">小弟喊话</button>
</div>
</template>
<script>
import bus from '../../utils/bus'
export default {
name: "b2",
components: {},
data() {
return {
msg:'我是小弟。'
};
},
methods: {
passData(val){
// 通过关键字去触发全局事件busEvent
bus.$emit('busEvent',val)
}
},
};
</script>
<style lang='less' scoped>
</style>
总结
以上就是vue中组件间通讯的7种方法。面试当中如果问起vue组件间通信,答出这7中应该这题能过了,下一篇就再整理一下vuex的相关知识以及使用。