前言
本章我们将介绍组件间是如何实现数据通信的 。包括父组件向子组件 、子组件向父组件 、兄弟组件 、非关系组件之间的数据通信 。
组件通信是组件式开发中非常重要的一部分 ,也是组件式开发中的难点 。
组件介绍
组件是 vue 最强大的功能之一 ,而组件实例的作用域是相互独立的 ,这就意味着不同组件之间的数据无法相互引用 。
我们需要使用特定的方式来实现组件间的数据通信 ,接下来让我们一个个介绍这几种类别的组件通信是如何实现的 。
一 、父传子
1. 父组件通过 props 传递数据给子组件
父组件通过 props 属性向子组件传递数据 。
子组件利用组件实例的 props 属性定义组件需要接收的参数 ,在使用组件时通过 attribute的方式传入参数 。
// 在子组件内定义组件接收一个参数 name
{
props: [name]
}
// 父组件使用组件时传递参数 name
<child :name="name"></child>
接下来我们看一个具体示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<parent></parent>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component(parent, {
template: <child :name="name"></child>,
data() {
return {
name: 句号
}
}
})
Vue.component(child, {
template: <div>{{name}}</div>,
props: [name]
})
var vm = new Vue({
el: #app,
data() {
return {}
}
})
</script>
</html>
代码解释
JS 代码第 14-18 行:定义了组件 child ,并用 props 接收一个参数 name 。
JS 代码第 4-12 行:定义了组件 parent ,在组件中使用 <child></child> 引用组件 ,并用 attribute 的方式将 name 传递给组件 child 。
在上面的例子中 ,组件 Child 接收参数 name ,name 可以是字符串 、数组 、布尔值 、对象等类型 。但有时候我们需要给接收的参数指定一个特殊的类型和默认值 ,接下来我们就来介绍一下如何指定 props 的类型和默认值 。
2. 定义props的类型和默认值
在上面的例子中 ,props 接收一个组件参数数组 。
实际上,props 也可以接收一个对象 ,对象key为组件接收参数的参数名 ,其值是一个对象,属性 type 用来指定参数的类型 ,属性 default 用来指定参数的默认值:
{
props: {
name: {
type: String,
default: 句号
}
}
}
接下来我们看一个具体示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<parent></parent>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component(parent, {
template: <div><child :name="name" /> <child/></div>,
data() {
return {
name: 慕课网
}
}
})
Vue.component(child, {
template: <div>{{name}}</div>,
props: {
name: {
type: String,
default: 句号
}
}
})
var vm = new Vue({
el: #app,
data() {
return {}
}
})
</script>
</html>
JS 代码第 11-19 行:定义了组件 child ,并用 props 接收一个字符串类型的参数 name ,其默认值是:句号。
JS 代码第 3-10 行:定义了组件 parent ,在组件中使用<child></child>两次引用组件 ,<child :name="name" /> 的方式传递 name 值 ,<child/> 使用默认的 name 值 。
TIPS: 注意 ,给数组和对象类型的 props设置默认值的时候 ,需要按照以下的写法:
props: {
detail: {
type: Object,
default: () => {
return {
name: 句号
}
}
},
loves: {
type: Array,
default: () => {
return []
}
}
}
二 、子传父
子组件通过 $emit 传递数据给父组件
介绍完父组件传递数据给子组件的方式 ,我们再来看看子组件是如何传递数据给父组件的 。
子组件通过 $emit 传递事件给父组件 ,父组件通过$on监听事件:
// 子组件定义事件
this.$emit(事件名称, 传递的参数) //例: this.$emit(add, 111)
// 父组件监听事件的触发
<child @事件名称="事件触发的方法"/>
具体示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<parent></parent>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component(parent, {
template: <div><child :name="name" :count="count" @add="add"/></div>,
data() {
return {
name: 句号,
count: 18
}
},
methods: {
// 父组件通过 @事件名 监听
// count 表示事件触发传递的参数
add(count) {
this.count = count
}
}
})
Vue.component(child, {
template: <div>我是:{{name}} , 我今年 {{count}}岁。<button @click="add">加一岁</button></div>,
props: {
name: {
type: String,
default: 句号
},
count: {
type: Number,
default: 18
}
},
methods: {
add(){
// add -> 触发的事件名
// this.count + 1 -> 触发事件时传递的参数
this.$emit(add, this.count + 1)
}
}
})
var vm = new Vue({
el: #app,
data() {
return {}
}
})
</script>
</html>
代码解释
JS 代码第 19-38 行:定义了组件 child ,该组件接收两个参数:1. 字符串类型的 name,默认值为:句号 。2. 数字类型的 age ,默认值为 18 。组件模版中 ,通过按钮点击事件触发 add 方法,该方法内部通过$emit触发事件 add ,并将 age + 1 的值作为参数传递 。
JS 代码第 3-18 行:定义了组件 parent ,在组件中使用<child :name="name" :age="age" @add="add"/>引用组件 ,并绑定 add 事件 ,当事件 add 触发时调用 methods 中的 add 函数 。
三 、非父子组件间数据传递
前面我们介绍了具有父子关系的组件是如何进行数据传递的 。但实际上 ,并不是所有的组件都是父子关系 ,组件间还有兄弟组件 、子孙组件 、无关系组件 ,那么这些组件间是如何进行通信的呢?
相信在学完本章前面的内容之后这个问题并不能难倒大家 。
对于兄弟组件的数据通信:它们有共同的父组件 ,我们可以通过父组件传递的方式实现数据通信 。
对于子孙组件的数据通信:可以通过 props 的方式向下逐层传递下去 ,也可以通过 $emit 将事件向上逐层传递 。
对于非关系组件的数据通信:通过使用一个空的Vue实例作为中央事件总线 。
1.通过公有的父组件进行非父子组件间的通信
假设现在有三个组件分别是<Parent> 、<ChildA>、<ChildB> ,其中组件<Parent>是<ChildA>和<ChildB>的父组件 ,<ChildA>和<ChildB>为兄弟组件 ,<ChildA>和<ChildB>组件间的通信可以借助<Parent>来间接传递 。它的流程大致是这样:
<ChildA>通过$emit将数据传递给<Parent>,<Parent>再通过props将数据传递给<ChildB> 。
具体示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<person @modify="modify"></person>
<detail :name="name" :count="count"/>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component(person, {
template: <div><div>姓名:<input type="text" v-model="name"/></div><div>年龄:<input type="text" v-model="count"/></div><button @click="modify">修改</button></div>,
data() {
return {
name: 句号,
count: 18
}
},
methods: {
modify() {
this.$emit(modify, {name: this.name, count: this.count})
}
}
})
Vue.component(detail, {
template: <div>我是:{{name}} , 我今年 {{count}}岁 。</div>,
props: {
name: {
type: String,
default: 句号
},
count: {
type: Number,
default: 18
}
},
methods: {
}
})
var vm = new Vue({
el: #app,
data() {
return {
name: 句号,
count: 18
}
},
methods: {
modify(detail) {
this.name = detail.name
this.count = parseInt(detail.count)
}
}
})
</script>
</html>
代码解释
JS 代码第 18-30 行:定义了组件 detail ,它从父组件接收 name 和 age 两个参数。
JS 代码第 3-17 行:定义了组件 person,它通过 $emit 将组件内输入的 name 和 age 传递给父组件 。
JS 代码第 38-41 行:接收了组件 person 传递过来的事件 ,并修改 name 和 age 。
HTML 代码第 3 行:将 name 和 age 传递给组件 detail。
2. 通过使用一个空的 Vue 实例作为中央事件总线
在Vue中可以使用 EventBus 来作为沟通桥梁的概念 ,就像是所有组件共用相同的事件中心 ,可以向该中心注册发送事件或接收事件 ,所以组件都可以上下平行地通知其他组件 。
首先我们需要做的是创建事件总线 ,并将它挂载到Vue原型上 ,在实例中通过this.bus.$emit发送事件 ,通过this.bus.$on接收事件
// 定义事件总线
let bus = new Vue()
Vue.prototype.bus = bus
// 定义发送事件
this.bus.$emit(事件名称, data)
// 定义接收事件 并在回调中接收参数
this.bus.$on(事件名称, (data) => {
})
接下来我们看一段具体示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<person></person>
<detail />
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
let bus = new Vue()
Vue.prototype.bus = bus
Vue.component(person, {
template: <div><div>姓名:<input type="text" v-model="name"/></div><div>年龄:<input type="text" v-model="count"/></div><button @click="modify">修改</button></div>,
data() {
return {
name: 句号,
count: 18
}
},
methods: {
modify() {
this.bus.$emit(modify, {name: this.name, count: this.count})
}
}
})
Vue.component(detail, {
template: <div>我是:{{name}} , 我今年 {{count}}岁 。</div>,
data() {
return {
name: 句号,
count: 18
}
},
mounted() {
this.bus.$on(modify, (detail) => {
this.name = detail.name
this.count = detail.count
})
}
})
var vm = new Vue({
el: #app,
methods: {
}
})
</script>
</html>
代码解释
JS 代码第 3-4 行:通过 new Vue() 创建一个 vue 实例 ,并将它挂载在 Vue 的原型上 。这样 ,在 vue 组件中可以通过 this.bus 访问到这个实例对象 。
JS 代码第 5-18 行:定义了组件 person ,当点击修改按钮的时候通过 this.bus.$emit 发送一个名为 modify 的事件 ,并将组件内输入的 name 和 age 作为参数传递 。
JS 代码第 19-33 行:定义组件 detail,在组件内部通过this.bus.$on监听名为 modify 的事件 ,当事件触发时执行修改操作 。
小结
在本章 ,我们介绍了组件间的通信方式,主要有以下知识点:
父组件通过 props 向子组件传递参数进行数据通信;
子组件通过 $emit 向父组件传递事件进行数据通信;
兄弟组件通过共同父组件进行数据通信;
通过使用一个空的 Vue 实例作为中央事件总线进行非关系层组件的数据通信 。
以上为个人经验 ,希望能给大家一个参考 ,也希望大家多多支持本站 。
声明:本站所有文章 ,如无特殊说明或标注 ,均为本站原创发布 。任何个人或组织 ,在未征得本站同意时 ,禁止复制 、盗用 、采集、发布本站内容到任何网站 、书籍等各类媒体平台 。如若本站内容侵犯了原著者的合法权益 ,可联系我们进行处理 。