文章目录
Vue 里面父子间的通信
一、父组件向子组件 传参
在 vue 里面,父组件可以向子组件 传递参数,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓
Pass props
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
}
</style>
</head>
<body>
<div id="app">
<cpn :memove="move" :memessage="message"></cpn>
</div>
<template id="cpn">
<div>
<p>{{memove}}</p>
<h2>{{memessage}}</h2>
</div>
</template>
<script src="../vue.js"></script>
<script>
/*
父子间的关系说明:
1) 父组件 通过 props 向子组件传递数据 传参 Pass props
*/
// 创建组件构造器
const cpn = {
template: '#cpn',
// 语法: props: ['父组件传递的自定义属性名(str)'],
// props: ['memove', 'memessage'],
props: {
// 1. 类型限制
// memove: Array, // 要求 memove 需是一个 数组
// memessage: String, // 要求 memessage 需是一个 字符串
// 2. 提供默认值 注意默认值,不是你 父组件没有这个值,而是你子组件,没有接受这个值,也就是,子组件只接受了 memove 这个数据
memessage: {
type: String,
default: '我是你爸爸',
required: true, // 表示 memessage 是一个必须传递的参数(数据),也就是你子组件,需要传递(接受)过来,不传,就报错
},
memove: {
type: Array,
// 当类型为 数组 或者 对象的时候,默认值必须是一个函数
default () {
return []
}
}
},
}
// 需求:vue 实例作为 父组件,先子组件 传递数据
const app = new Vue({
el: '#app',
data: {
message: '你好呀',
move: ['海王', '海尔兄弟', '星际跳跃', '八佰']
},
components: {
cpn
}
});
/*
父向子传参说明:
1) 父组件将数据传递给子组件
2) 子组件设置 动态属性,来接收父组件传递过来的数据 <cpn :memove="move" :memessage="message"></cpn>
3) 在 子组件 模板里面,使用动态接收过来的变量,也就是 父组件传递过来的参数
4) props 不仅仅支持数组,还可以使用 对象,当需要对传入的参数进行验证的时候,也就是对 props进行类型验证的时候,就需要使用 对象的写法了
验证支持的数据类型:
String
Number
Boolean
Array
Object
Date
Function
Symbol
5) props 中接收到的数据,最终会挂载到 实例上(作为实例上的属性),data中的数据,methods中的方法,computed中的计算属性,都会
编译成 实例上的属性和方法,所以注意不要同名
*/
</script>
</body>
</html>
父向子传参总结:
- 通过給 子组件设置 props ,props里面写的是 自定义属性名称,props 里面可以 限制参数类型 或者 提供参数默认值
- 在 子组件 上使用 v-bind:props里面自定义属性名=‘父组件传递的参数’,来实现,父组件向子组件传递参数
- 大致流程:
(1) 在 子组件上 使用 props 自定义属性,用于接收 父组件 传递过来的参数 。
(2)props 里面可以限制 (验证) 接收父组件传递过来 参数的 类型,以及 是否必须传递这个参数、参数默认值,但是需要注意 当参数类型为数组 或者对象 的时候,默认值必须是一个 函数
(3) 在 父组件 上 使用 v-bind 绑定 自定义属性,以及父组件要传递的参数,如: v-bind:memsg=“msg” 这 memsg 就是在 子组件 props 里面 自定义的属性名称
(4)然后你就可以 在子组件 上愉快的 使用 父组件传递过来的参数了
二、子组件向父组件通信
在 vue 里面,子组件可以向父组件 通信,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓
$emit Events
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
}
#app {
width: 500px;
height: 200px;
border: 1px solid black;
margin: 150px auto;
}
</style>
</head>
<body>
<!-- 父组件 -->
<div id="app">
<cpn @itemclick="cpnClick"></cpn>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<button v-for="item in classifys" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script src="../vue.js"></script>
<script>
// 1. 子组件
const cpn = {
template: '#cpn',
props: {
// 数据限制,以及提供默认值
carr: {
type: Object,
default () {
return {}
}
}
},
data() {
return {
classifys: [{
id: 1,
name: '手机数码'
},
{
id: 2,
name: '家用家电'
},
{
id: 3,
name: '电脑办公'
},
{
id: 4,
name: '精品男装'
},
]
}
},
methods: {
btnClick(item) {
// console.log(data); // 点击哪一个,就打印那一条数据
// 通过 自定义事件,发射信号给 父组件
// 语法: this.$emit('自定义事件名称',发射过去的参数)
this.$emit('itemclick', item);
}
},
}
// 2. 父组件
const app = new Vue({
el: '#app',
data: {
message: '你好呀',
},
components: {
cpn
},
methods: {
cpnClick(data) {
alert(data.name)
}
}
});
/*
子组件向父组件通信说明:
1) 子组件不会处理复杂的 数据操作,会将复杂的数据操作 交予 父组件操作
2) 子组件,通过用户触发了某个时间,以及触发哪个事件,将其返回给 父组件,让父组件处理(甩锅侠)
3) 例如:用户点击了 '精品男装',那么 子组件,将 点击了 '精品男装' 这个 信息,传递给 父组件,让父组件处理复杂数据,然后渲染页面到 '精品男装'
4) 组件里面没有 事件对象,在 cpnClick 函数里,html中对中函数没有 传递参数,若是在别的地方,则会将 事件对象,当参数传递给 data,但是这里 是将
item 传递给 data,也就是,这里 是之前的 参数问题之事件对象的 特例,html里面不写参数的时候,传递的是 子组件发射过来的参数(数据)
*/
</script>
</body>
</html>
子向父通信总结:
- 通过給 子组件设置 一个方法,方法内 发射一个 自定义事件和参数,如 :this.$emit(‘自定义事件’,参数)
- 在 父组件 上使用 v-on:自定义事件=“父组件处理传递过来的信息方法”
- 大致流程:
(1) 在 子组件上 定义一个方法,方法内发射一个 自定义事件,和参数 到父组件上,如: this.$emit(‘aaa’,10) 这里 aaa 就是自定义属性名称,10就是参数
(2)在 父组件 上面,使用 v-on 来接收 子组件 发射过来的 信息,如: v-on:aaa=“父组件处理信息的方法”
(3) 在 父组件处理信息的方法 上,需要注意的是 ,一般我们在 某个方法上 需要使用一个参数,可是 调用的时候,没有传递的时候,vue里面会将触发该事件的 事件对象,传递过来,给 这个方法使用,但是在 vue组件里面,没有 事件对象一说法的,他会将 发射过来的参数,当做默认参数,传递过来,这就是为什么上述代码里面 我没有给 cpnClick 传递参数的原因
(4)然后你就可以 在父组件 上愉快的 处理 子组件传递过来的信息了
三、兄弟组件间的通信
在 vue 里面,兄弟组件之间也是可以 通信的,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓
eventBus 事件中心总线
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
}
</style>
</head>
<body>
<div id="app">
<cpn1></cpn1>
<hr>
<cpn2></cpn2>
</div>
<template id="c1">
<div>
<h2>{{mesaage}}</h2> <br>
<button @click="btnClick">点击,向老二传递数据</button>
</div>
</template>
<template id="c2">
<div>
<h2>{{mesaage}}</h2>
<h1>{{hint}}</h1>
</div>
</template>
<script src="../vue.js"></script>
<script>
// 3. 创建 事件中心总线 eventBus
const bus = new Vue();
// 1. 老大组件
const cpn1 = {
template: '#c1',
data() {
return {
mesaage: '我是老大'
}
},
methods: {
btnClick() {
bus.$emit('aaa', this.mesaage)
}
},
}
// 2. 老二组件
const cpn2 = {
template: '#c2',
data() {
return {
mesaage: '我是老二',
hint: ''
}
},
mounted() {
bus.$on('aaa', (data) => {
this.hint = data;
})
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好呀'
},
components: {
cpn1,
cpn2
}
});
/*
兄弟间通信说明:
1) 利用第三方 实例,来实现 兄弟之间的通信
2) 在 子组件向父组件通信的时候,是子组件 定义一个自定义事件,并通过 this.$emit 发射出信息,而父组件会接受这个信息 @自定义事件="父组件处理事件"
3) 兄弟间组件通信,仿照子组件向父组件通信,原则上是:谁发射这个信息,就通过谁来 用 $on 来接收这个数据。只不过,这里使用第三方 实例来 发射和接收
4) 就相当于,原生里面 有的时候,this 不可以使用,就 that=this,一个道理,原先的 子 向 父通信,是利用 this 发射的,也就是子组件自己发射的,但是在
兄弟里面,无法在 兄弟2 里面使用 兄弟1的this,所以使用 第三方实例(事件中心总线) 来做
*/
</script>
</body>
</html>
兄弟组件通信总结:
- 兄弟组件间的通信,类似于 子先父通信,但是在兄弟组件里面,无法直接发射信息到 对应兄弟组件上,这就的使用 一个第三方平台了 -------- eventBus 事件中心总线
- 原理就是 利用 这个 eventBus 发射信息,再去要接收这个信息的兄弟组件上用 eventBus 接收一下,就好了
- 大致流程
(1) 创建 事件中心总线 eventBus 实例 bus
(2) 用 bus.$emit(‘自定义事件’,参数) 发送要发送的信息
(3) 用 bus.$on(‘自定义事件’,回调函数) 来接收 发送过来的数据
四、父组件访问子组件
在 vue 里面,父组件可以访问子组件上的内容,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓
方法一:$children 不建议使用
方法二:$refs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
}
</style>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
<cpn2 ref="aaa"></cpn2>
<cpn></cpn>
<button @click="btnClick()">点击切换内容</button>
</div>
<template id="cpn">
<div>
<h2>我是子组件1</h2>
<h2>{{msg}}</h2>
</div>
</template>
<template id="cpn2">
<div>
<h2>我是子组件2</h2>
<h2>{{msg}}</h2>
</div>
</template>
<script src="../vue.js"></script>
<script>
/*
父组件 访问 子组件说明:
1) 父组件 使用 $children 访问子组件, $children 打印出来的是一个数组,若是有多个子组件,就是利用
索引号,去拿到 所需要的的数据,如:this.$children[5].msg,但是一旦牵涉到索引号,就危险了,可能后期
我在 第5个组件前初入另一个组件,那么索引号就改了,牵一发而动全身,下面获取 $children 的索引号也得改,所以
不建议使用 这种方式获取 子组件的 内容
2) 父组件 使用 $refs 访问子组件 在 子组件 上设置 ref='xxx',而后再获取的时候 this.$refs.xxx 就可以获取到 定义
ref='xxx' 那条数据里面的内容
3) 所谓的 访问,就是父组件,使用子组件上面的 方法、数据、计算属性等等
4)
*/
const cpn = {
template: '#cpn',
data() {
return {
msg: '我是你爸爸1'
}
},
methods: {
log() {
console.log('这是子组件打印的内容');
}
},
}
const cpn2 = {
template: '#cpn',
data() {
return {
msg: '我是你爸爸2'
}
},
methods: {
log() {
console.log('这是子组件2打印的内容');
}
},
}
const app = new Vue({
el: '#app',
data: {
message: '你好呀'
},
components: {
cpn,
cpn2
},
methods: {
btnClick() {
// 1. 方法一
// console.log(this.$children); // [VueComponent] 打印的是 子组件上所有东西,是一个数组,比如要使用 子组件的 msg 就是 this.$children[0].msg
// console.log(this.$children[3].msg); // 我是你爸爸2
// 1. 方法二
// console.log(this.$refs.aaa); // aaa 上的内容
this.$refs.aaa.log(); // 调用 aaa 子组件上面的 log 方法
}
},
});
</script>
</body>
</html>
父组件访问子组件总结:
- 使用 $children[index] 方法获得子组件上的内容,但是 不建议使用,以为涉及到了索引号,即在使用多个组件的时候,删除某一个组件,或者添加一个组件,都会改变索引号,不利于代码的维护
- 使用 $refs方法,在组件上设置, ref=‘aaa’,在父组件上 用 $refs.aaa 获得该组件上的内容,建议使用
五、子组件访问父组件/根组件
在 vue 里面,子组件也可以访问父组件上的内容,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓
访问父组件:$parent
访问根组件:$root
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
}
</style>
</head>
<body>
<!-- 父组件 -->
<div id="app">
<cpn>
</cpn>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<h2>我是子组件</h2>
<h2>{{msg}}</h2>
<hr>
<ccpn></ccpn>
</div>
</template>
<!-- 子子组件 -->
<template id="ccpn">
<div>
<h2>我是子子组件</h2>
<h2>{{msg}}</h2>
<button @click="btnClick()">点击切换内容</button>
</div>
</template>
<script src="../vue.js"></script>
<script>
/*
子组件 访问 父组件说明:
1) 子组件使用 $parent 访问 父组件上的 所有内容
2) 注意 子组件访问 父组件上面的内容,不可以跨级访问,只能由 儿子,访问 父亲,不可以儿子访问 爷爷
3) 实际开发过程中,不建议使用 子组件访问 父组件上的内容,因为,我们需要做到 子组件复用,打个比方说:
你讲 子组件1 放到 父组件a里面,并且使用了 父组件a 里面的数据,但是你讲 子组件1,放到 父组件b里面,
b 里面可是没有 a 里面的数据,你再获取不到 a 里面的数据了,不能有奶就是娘,这样耦合性太强,不利于模块间开发
4) $root 访问的是 根组件,也就是 vue 实例
*/
// 1. 孙子级别 组件
const ccpn = {
template: '#ccpn',
data() {
return {
msg: '我是 vue 的孙子'
}
},
methods: {
btnClick() {
// console.log(this.$parent.msg); // 打印的是 '我是 vue 的儿子' 只可以访问到父组件,访问不到 根组件
console.log(this.$root.message); // 打印的是 '你好呀' 直接 访问到 根组件
},
}
}
// 2. 儿子级别 组件
const cpn = {
template: '#cpn',
data() {
return {
msg: '我是 vue 的儿子'
}
},
methods: {
log() {
console.log('子子');
},
},
components: {
ccpn
}
}
// 3. 根组件
const app = new Vue({
el: '#app',
data: {
message: '你好呀'
},
components: {
cpn,
},
methods: {
log() {
console.log('这是父组件打印的内容');
}
},
});
</script>
</body>
</html>
子组件访问父组件/根组件总结:
- 使用 $parent 可以访问到 父组件上的内容,注意的是,它只可以访问到 父组件,不可以访问到父组件之外的组件
- 使用 $root,可以访问到 根组件上的内容,也就是 vue 实例上的内容