共计 6882 个字符,预计需要花费 18 分钟才能阅读完成。
前言
本章咱们将介绍组件间是如何实现数据通信的。包含父组件向子组件、子组件向父组件、兄弟组件、非关系组件之间的数据通信。组件通信是组件式开发中十分重要的一部分,也是组件式开发中的难点。
组件介绍
组件是 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 实例作为地方事件总线进行非关系层组件的数据通信。
六年代码两茫茫,不思量,自难忘
6 年资深前端主管一枚,分享技术干货,我的项目实战经验,面试领导
关注博主不迷路~