vue组件通信的方法
前言
组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。但是,在实际的项目开发中,形如页面和页面之间需要通信一样,Vue 组件和组件之间肯定也需要互通有无、共享状态。接下来在了解组件通信之前,我们先来了解一下组件间的几种关系:
如图所示:
- A 和 B、B 和 C、B 和 D 都是父子关系
- C 和 D 是兄弟关系
- A 和 C 是隔代关系(可能隔多代)
针对不同的组件关系我们会有更适合的通信方式,接下来就让我们来看一下吧。
组件通信
1、父组件向子组件传值props
props 以单向数据流的形式可以很好的完成父子组件的通信。所谓单向数据流:就是数据只能通过 props 由父组件流向子组件,而子组件并不能通过修改 props 传过来的数据修改父组件的相应状态。至于为什么这样做,Vue 官网做出了解释:
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
——Vue 官网
<!--父组件--> <template> <div> <children :child="message"></children> //前者自定义名称便于子组件调用,后者要传递的数据名 </div> </template> <script> import children from "@/views/send/children";//引入子组件 export default { name: "parent", data(){ return{ message: '我是父组件的值!' } }, components:{ children }, } </script>
<!--子组件-->
<template>
<div>
<h1>{{child}}</h1>
</div>
</template>
<script>
export default {
name: "children",
props:["child"], //也可以使用下面的对象类型接收数据
props:{
child:{
type:String,
require:true //表示用这个组件的时候就必须传值child,否则报错
}
},
}
</script>
2、子组件向父组件传值 $emit
<!--子组件--> <template> <div> <input type="text" v-model="message"> <button @click="click">Send</button> </div> </template> <script> export default { name: "children", data(){ return{ message:'我是子组件的值!' } }, methods:{ click(){ this.$emit('childFn',this.message);//自定义事件名childFn } } } </script>
<!--父组件--> <template> <div> <children @childFn="parentFn"></children> //注意在组件上要对方法名进行绑定 <p>子组件传来的值:{{paMess}}</p> </div> </template> <script> import children from "@/views/send/children"; export default { name: "Cart", data(){ return{ paMess:'' } }, components:{ children }, methods:{ parentFn(payload){ this.paMess = payload;//payload就是子组件传来的值,父组件接收 } } } </script>
3、ref 和 $refs 传值
- 父组件向子组件传值
<!--父组件--> <template> <div> <!-- 点击触发方法将数据传给子组件--> <button @click="sendData">send</button> <children ref="myChild"></children> </div> </template> <script> import children from "@/views/send/children"; export default { name: "parent", data(){ return{ } }, components:{ children }, methods:{ sendData(){ //父组件触发子组件的init方法 this.$refs.myChild.init("waq",22) } } } </script>
<!--子组件--> <template> <div> <h1>{{name}}</h1> <h1>{{age}}</h1> </div> </template> <script> export default { name: "children", data(){ return{ name: '', age: '' } }, methods:{ init(name,age){ this.name = name; this.age = age; } } } </script>
- 父组件还可以通过ref获取子组件的值,即子组件向父组件传值
<!--父组件--> <template> <div> <!-- 点击触发方法获取子组件的数据--> <button @click="getData">send</button> <children ref="myChild"></children> <p>{{parMes}}</p> </div> </template> <script> import children from "@/views/send/children"; export default { name: "parent", data(){ return{ parMes:'', } }, components:{ children }, methods:{ getData(){ //父组件获取子组件message值 this.parMes = this.$refs.myChild.message; } } } </script>
<!--子组件--> <template> <div> </div> </template> <script> export default { name: "children", data(){ return{ message:'我是子组件的值!!' } }, } </script>
4、$parent 和 $children
$parent
就是父组件的实例对象,
$children
就是当前实例的直接子组件实例了,不过这个属性值是数组类型的,且并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children
来进行数据绑定,考虑使用一个数组配合 v-for
来生成子组件,并且使用 Array 作为真正的来源。父组件也可以通过this.$children 访问它所有的子组件
<!--父组件--> <template> <div> <button @click="changeChild">change</button> <children></children> </div> </template> <script> import children from "@/views/send/children"; export default { name: "parent", data(){ return{ message:'hello' } }, components:{ children }, methods:{ changeChild(){ this.$children[0].mymessage = 'hello'; } } } </script>
<!--子组件--> <template> <div> <input type="text" v-model="mymessage" @change="changeValue"> </div> </template> <script> export default { name: "children", data(){ return{ mymessage: this.$parent.$message } }, methods: { changeValue(){ this.$parent.message = this.mymessage;//通过如此调用可以改变父组件的值 } } } </script>
在上面实例代码中,分别定义了 parent 和 child 组件,这两个组件是直接的父子关系。两个组件分别在内部定义了自己的属性。在 parent 组件中,直接通过 this.$children[0].mymessage = 'hello';
给 child
组件内的 mymessage
属性赋值,而在 child 子组件中,同样也是直接通过this.$parent.message
给 parent
组件中的 message
赋值,形成了父子组件通信。
关于此方法的通信会在下一篇博客详细介绍。
参考文章:https://juejin.cn/post/6844903784963899405#heading-7