vue组件之间通信
1、vue组件的目的
1、降低整体的复杂度(粗粒度降解成细粒度),提高代码的可读性和可维护性,
2、提高局部代码的可复用性
当整体被拆解成了一块一块的组建以后,所有的组件都是独立存在的,如果需要关联起来,就需要用到组建中的相互传值,相互传值分为两种
1、父子组件之间的传值
2、跨组件之间的传值
2、父子组件之间通信
大部分的通讯方式都是父子组件之间的传值
(1)prop 与 event
父组件传递属性给子组件,子组件通过props对象来声明父组件传过来的值,例如
// 父组件中
<template>
<div>
<!-- 使用子组件 -->
<son num="1"></son>
</div>
</template>
<script>
import son './son'
export default {
// 注册子组件
components: {son}
}
</script>
// 子组件中
<template>
<div>
<!-- 使用父组件传递过来的值 -->
<h1>{{ num }}</h1>
</div>
</template>
<script>
export default {
//声明父组件传过来的值
props: [ 'num' ]
}
</script>
(2)style,class属性
如果父组件向子组件传递style与class属性,那么这两个属性,就会合并到子组件的根元素中,使用的范围比较窄,主要的目的就是父组件给子组件传递样式。
// 父组件中
<template>
<div>
<!-- 使用子组件,并在子组件上设置了class, style属性 -->
<son style="color: #fff" class="father"></son>
</div>
</template>
<script>
import son './son'
export default {
// 注册子组件
components: {son}
}
</script>
// 最后子组件中就变成了以下的样子
<template>
<div class="father" style="color: #fff">
<h1>我是一个啥都没有的子组件</h1>
</div>
</template>
<script>
export default {}
</script>
如果子组件中已经有了class和style这两个属性
// 子组件中
<template>
<div class="son" style="font-size: 16px">
<h1>我是一个啥都没有的子组件</h1>
</div>
</template>
<script>
export default {}
</script>
那么就会进行合并
// 最后子组件中就变成了以下的样子
<template>
<div class="son father" style="font-size: 16px; color: #fff">
<h1>我是一个啥都没有的子组件</h1>
</div>
</template>
<script>
export default {}
</script>
(3)attribute
如果父组件向子组件传递了属性,但是子组件中并没有声明这个属性,那么这些没有被声明的属性就是attribute,这些没有被子组件声明的属性就会被添加到子组件的根元素上,例如
// 父组件中
<template>
<div>
<!-- 使用子组件,并在子组件上传递 nameA, nameB两个属性 -->
<son nameA="A" nameB="B"></son>
</div>
</template>
<script>
import son './son'
export default {
// 注册子组件
components: {son}
}
</script>
// 子组件中
<template>
<div >
<h1>父组件给我传递了两个属性,但是我并没有在props中声明</h1>
</div>
</template>
<script>
export default {}
</script>
最后的渲染结果为
// 子组件中
<template>
<!-- nameA, nameB两个属性就会被添加到根元素上 -->
<div nameA="A" nameB="B">
<h1>父组件给我传递了两个属性,但是我并没有在props中声明</h1>
</div>
</template>
<script>
export default {}
</script>
在子组件中,可以通过this.$attrs这个对象,获取从父组件中传过来但是子组件没有声明的值。注意:style和class除外
// 子组件中
<template>
<!-- nameA, nameB两个属性就会被添加到根元素上 -->
<div nameA="A" nameB="B">
<h1>父组件给我传递了两个属性,但是我并没有在props中声明</h1>
</div>
</template>
<script>
export default {
created() {
// 通过this.$attrs,得到 nameA, nameB 这两个属性和属性值
console.log(this.$attrs)
}
}
</script>
注意:子组件可以通过inheritAttrs: false,将attribute禁止添加到根元素上面,但是不影响this.$attrs中的获取
(4)natvie修饰符
父组件可以通过native修饰符,将事件注册到子组件的根元素上,让子元素去使用。例如
// 子组件中
<template>
<div >
<h1>我是子元素,我很干净,啥也没有,事件就更没有了</h1>
</div>
</template>
<script>
export default {}
</script>
// 父组件中
<template>
<div>
<!-- 在子组件上注册一个click事件,
并使用.natvie修饰,这样子组件
就可以使用了 -->
<son @click.natvie="sonClick"></son>
</div>
</template>
<script>
import son './son'
export default {
// 注册子组件
components: {son},
methods: {
sonClick() {
console.log('这是父组件在子组件上注册的点击方法!')
}
}
</script>
(5)sync修饰符
sync修饰符是一个语法糖,用于双向数据绑定,一个组件可以多个属性用.sync修饰符,可以同时"双向绑定多个“prop”,v-model只能对一个数据进行双向数据绑定。注意:vue3将v-model和sync修饰符合并了
不使用sync修饰 例如
// 子组件中
<template>
<div>
<h1>{{ num1 }}</h1>
<button @click="$emit('update:num1', num1 - 1)">减</button>
<button @click="$emit('update:num1', num1 + 1)">加</button>
<h1>{{ num2 }}</h1>
<button @click="$emit('update:num2', num2 - 1)">减</button>
<button @click="$emit('update:num2', num2 + 1)">加</button>
</div>
</template>
<script>
export default {
props: ['num1', 'num2']
}
</script>
// 父组件中
<template>
<div>
<!-- 如果触发num1的时候,就赋值num1 -->
<!-- 如果触发num2的时候,就赋值num2 -->
<son :num1="n1"
:num2="n2"
@update:num1="n1 = $event"
@update:num2="n2 = $event"
></son>
</div>
</template>
<script>
import son './son'
export default {
// 注册子组件
components: {son},
data() {
return: {
n1: 1,
n2: 2
}
}
}
</script>
使用sync修饰符可以简化成以下写法:
// 父组件中
<template>
<div>
<!-- 使用sync修饰符可以简化成一下写法 -->
<son :num1.sync="n1"
:num2.sync="n2"
></son>
</div>
</template>
<script>
import son './son'
export default {
// 注册子组件
components: {son},
data() {
return: {
n1: 1,
n2: 2
}
}
}
</script>
(6)ref
父组件可以通过ref获取到子组件的实例信息,例如
// 父组件中
<template>
<div>
<!-- 使用ref获取子组件实例 -->
<son ref="sonRef"></son>
</div>
</template>
<script>
import son './son'
export default {
// 注册子组件
components: {son},
mounted() {
// 获取子组件的实例信息,可以调用子组件的方法或者属性
console.log(this.$refs.sonRef)
}
}
</script>
(7)$listeners
子组件可以通过$listeners,获取父组件传递过来的所有事件处理函数。
3、跨组件通信
(1)Provide 与 Inject
Provide、Inject是vue官方提供的,可以跨组件应用,但是兄弟组件不能使用该方法,父子,祖先组件是可以使用的,一般应用于一些公共的组件库。
官方文档(详细): https://cn.vuejs.org/v2/api/?#provide-inject
(2)vuex
大型项目可以使用vuex做数据之间的传输和共享
(3)router
组件改变了地址栏,可以将地址栏作为数据传输的路径。