组件通信#
组件通信,就是指组件与组件之间的数据传递
- 组建的数据是独立的,无法直接访问其他组件的数据
- 想使用其他组件的数据就需要组件通信
不同的组件关系和组件通信方案分类#
组件关系分类:#
- 父子关系
- 非父子关系
组件通信解决方案#
-
父子关系:
props
和$emit
-
非父子关系:
-
provide
&inject
eventbus
-
-
通用解决方案:
Vuex
(适合复杂业务场景)
父子组件通信#
-
父组件通过
props
将数据传递给子组件 -
子组件利用
$emit
通知父组件修改更新
父组件传数据给子组件#
准备子组件SonBox.vue
父组件准备的数据用
v-bind
以属性方式绑定到子组件标签上,当然v-bind可以省略只写冒号
<!-- App.vue -->
<template>
<div class="App">
App组件(父组件)
<!-- 1.给组件标签,添加属性的方式传值 -->
<SonBox v-bind:title="myTitle" :abc="father"></SonBox>
</div>
</template>
<script>
import SonBox from './components/SonBox.vue';
export default {
data() {
return {
myTitle: 'a son',
father: 'App.vue',
};
},
components: {
SonBox,
},
};
</script>
子组件要使用父组件的数据,就需要使用
props
进行接收数据,
注意props中列表项的值要与子组件中绑定的属性名一致
传值和接收值完成后就可以在子组件中正常使用了
<!-- SonBox.vue -->
<template>
<div>
<!-- 3.渲染使用 -->
子组件{{ title }}
<div>父组件是{{ abc }}</div>
</div>
</template>
<script>
export default {
// 2.通过props进行接收
props: ['title', 'abc'],
};
</script>
子组件传数据给父组件#
子组件利用
$emit
通知父组件,进行修改更新
子组件调用父组件传递的回调函数,将数据作为参数传递给该函数
<!-- SonBox.vue -->
<template>
<div>
<!-- 1.3.渲染使用 -->
子组件{{ title }}
<div>父组件是{{ abc }}</div>
<button @click="changeFn">修改title</button>
</div>
</template>
<script>
export default {
// 1.2.通过props进行接收
props: ['title', 'abc'],
methods: {
changeFn() {
// 2.1.通过$emit,向父组件发送消息通知
this.$emit('changeTitle', 'andy');
},
},
};
</script>
<style lang="less" scoped>
div {
margin: 20px;
border: 1px solid red;
}
</style>
在父组件中,通过在子组件的标签上监听相应事件,并在事件处理函数中获取子组件传递的数据
<template>
<div class="App">
App组件(父组件)
<!-- 1.1给组件标签,添加属性的方式传值 -->
<!-- 2.2父组件对消息进行监听 -->
<SonBox v-bind:title="myTitle" :abc="father" @changeTitle="handleChange"></SonBox>
</div>
</template>
<script>
import SonBox from './components/SonBox.vue';
export default {
data() {
return {
myTitle: 'a son',
father: 'App.vue',
};
},
components: {
SonBox,
},
methods: {
// 2.3提供处理函数,提供逻辑
handleChange(newTitle) {
this.myTitle = newTitle;
},
},
};
</script>
<style lang="less"></style>
prop校验#
有时父组件传递给子组件的数据不是子组件要求的数据类型
比如一个进度条组件的进度数据是一个正整数,而为了避免父组件传递的是字符型数据而无法使用的情况,就需要使用
prop校验
为组件的
prop
指定
验证要求
,不符合要求,控制台就会有
错误提示
,帮助开发者快速发现错误
语法:
- 类型校验(常用)
- 非空校验
- 默认值
- 自定义校验
类型校验#
props:{
校验的属性名:类型 // Number String Boolean Array Function ...
}
以进度条为例
准备进度条组件
BaseProgress.vue
,对于进度条所需数据
w
指定其类型为
String
,结果就会发现在控制台打印出了错误信息
其它校验#
完整写法,将要校验的属性名的值写成一个对象,在其中写校验规则
使用完整写法,可以进行更多方式的校验,甚至自定义校验规则
props: {
校验的属性名: {
type: 类型, // Number String Boolean ...
required: true, // 是否必填
default: 默认值,
validator(value) {
// 自定义校验逻辑
return 是否通过校验;
},
},
},
完整代码
App.vue
<template>
<div class="app">
<BaseProgress :w="width"></BaseProgress>
</div>
</template>
<script>
import BaseProgress from './components/BaseProgress.vue';
export default {
data() {
return {
width: 30,
};
},
components: {
BaseProgress,
},
};
</script>
<style></style>
BaseProgress.vue
如下对数据类型、非空、默认值都做了校验,并且自定义了数据范围的校验规则
<template>
<div class="base-progress">
<div class="inner" :style="{ width: w + '%' }">
<span>{{ w }}%</span>
</div>
</div>
</template>
<script>
export default {
// props: ['w'],
// 1.基础写法(类型校验)
// props: {
// w: String,
// },
// 2.完整写法(类型、是否必填、默认值、自定义校验)
props: {
w: {
type: Number,
required: true,
default: 50,
validator(value) {
if (value >= 0 && value <= 100) {
return true;
} else {
console.log('传入的prop w,必须是0-100的数字');
return false;
}
},
},
},
};
</script>
<style scoped>
.base-progress {
height: 26px;
width: 400px;
border-radius: 15px;
background-color: #272425;
border: 3px solid #272425;
box-sizing: border-box;
margin-bottom: 30px;
}
.inner {
position: relative;
background: #379bff;
border-radius: 15px;
height: 25px;
box-sizing: border-box;
left: -3px;
top: -2px;
}
.inner span {
position: absolute;
right: 0;
top: 26px;
}
</style>
prop&data 单向数据流#
共同点:都可以给组件提供数据。
区别:
-
data
的数据是 自己的 ,随便改 -
prop
的数据是 外部的 ,不能直接改,要遵循 单向数据流 ,谁提供的数据谁修改
以计数器组件为例
若计数器的值为组件本身的数据,那在组件中点击就可以直接修改
然鹅实际开发中,类似计数器的数据一般由外部提供,那就不能直接count++/count--修改了
而是通过按钮绑定点击事件,用
this.$emit
通知父组件修改数据
BaseCount.vue
<template>
<div class="base-count">
<button @click="handleSub">-</button>
<span>{{ count }}</span>
<button @click="handleAdd">+</button>
</div>
</template>
<script>
export default {
// 1.自己的数据随便修改 (谁的数据 谁负责)
// data () {
// return {
// count: 100,
// }
// },
// 2.prop外部传过来的数据 不能随便修改
props: {
count: Number,
},
methods: {
// 子组件通知父组件修改数据,然后数据更新视图
handleAdd() {
// 子传父this.$emit(事件名,参数)
this.$emit('changeCount', this.count + 1);
},
handleSub() {
this.$emit('changeCount', this.count - 1);
},
},
};
</script>
<style>
.base-count {
margin: 20px;
}
</style>
在父组件中子组件标签上绑定事件处理函数,接收参数对数据进行修改
App.vue
<template>
<div class="app">
<BaseCount :count="count" @changeCount="handleChange"></BaseCount>
</div>
</template>
<script>
import BaseCount from './components/BaseCount.vue';
export default {
components: {
BaseCount,
},
data() {
return {
count: 100,
};
},
methods: {
handleChange(newCount) {
this.count = newCount;
},
},
};
</script>
<style></style>
单向数据流 :父组件的prop更新,会单向向下流动,影响到子组件