前面我们知道了父组件向子组件传值通过props,接下来我们再总结下子组件传递给父组件。
子组件传递给父组件
什么情况下子组件需要传递值给父组件呢?
- 当子组件有一些事件发生的时候,而父组件需要更改展示的内容,那么就需要子组件向父组件传递值;
- 当子组件需要传递一些内容给父组件的时候;比如:父组件跳转时需要子组件的值传递到下一个页面;
vue2中的用法(vue3也可以使用):
// App.vue
<template>
<div>
<h2>当前数为: {{count}}</h2>
<Child @increment="increment" @decrement="decrement"></Child>
</div>
</template>
<script>
import Child from './components/Child.vue'
export default {
name: 'App',
components: {
Child
},
data() {
return {
count: 520
}
},
methods: {
increment(value) {
this.count += value;
},
decrement(value) {
this.count -= value;
}
}
}
</script>
// Child.vue
<template>
<button @click="increment">加1</button>
<button @click="decrement">减1</button>
</template>
<script>
export default {
name: 'Child',
methods: {
increment() {
this.$emit("increment", 2) // 可以在后面接上多个参数,用逗号隔开 比如:this.$emit("increment", 2, 3, 'hello')
},
decrement() {
this.$emit("decrement", 2)
}
}
}
</script>
vue3中第一种用法(通过数组形式):
// App.vue
<template>
<div>
<h2>当前数为: {{count}}</h2>
<Child @addNum="increment" @subNum="decrement"></Child>
</div>
</template>
<script>
import Child from './components/Child.vue'
export default {
name: 'App',
components: {
Child
},
data() {
return {
count: 520
}
},
methods: {
increment(value) {
this.count += value;
},
decrement(value) {
this.count -= value;
}
}
}
</script>
// Child.vue
<template>
<button @click="increment">加2</button>
<button @click="decrement">减2</button>
</template>
<script>
export default {
emits: ["addNum", "subNum"],
name: 'Child',
methods: {
increment() {
this.$emit("addNum", 100)
},
decrement() {
this.$emit("subNum", 100)
}
}
}
</script>
效果和上面一样。
第二种用法(通过对象形式):(主要是为了进行参数的验证)
// Child.vue
<template>
<button @click="increment">加</button>
<button @click="decrement">减</button>
<button @click="setOnePar">传单个参数</button>
<button @click="setOtherPar">传递多个参数</button>
</template>
<script>
export default {
emits: {
addNum: null,
subNum: null,
setNum: payload => {
console.log(payload) // 这儿打印的就是下方传递的值
return true
},
setSomePar: (num, firstName, lastName) => {
console.log(firstName + '-' + lastName) // Hello-Vue3
if (num > 100) {
return true
} else {
return false // 如果是return fasle的,那么会在出现警告,如下图
}
}
},
name: 'Child',
data() {
return {
num: 100
}
},
methods: {
increment() {
this.$emit("addNum", this.num)
},
decrement() {
this.$emit("subNum", this.num)
},
setOnePat() {
this.$emit("setNum", this.num)
},
setOtherPar() {
this.$emit("setSomePar", this.num, "Hello", "Vue3")
}
}
}
</script>
上面所述,传入的num值为100,验证不通过,那么就会出现下面的警告。当return true ,警告就会消失,通过这个能够快速定位到自己传递的值是否满足条件。
那不是父子组件该如何传值呢?(父与子孙)
这是官方提供的一幅图,意思是在上级定义一个provide,那么只有在这一级下方的子孙组件才能够通过inject拿到值,而同级兄弟组件无法拿到。下面通过一个简单例子来演示一下用法:
// App.vue
<template>
<div>
<Child></Child>
</div>
</template>
<script>
import Child from './components/Child.vue'
export default {
provide: { // 通过provide向子孙注入一些参数和参数值。
name: '帅哥',
age: 1
},
name: 'App',
components: {
Child
},
data() {
return {
count: 520
}
},
}
</script>
在Child组件中再定义一个子组件,也就是孙组件。
// Child.vue
template>
<HelloWorld />
</template>
<script>
import HelloWorld from './HelloWorld.vue'
export default {
name: "Child",
components: {
HelloWorld
}
</script>
孙组件通过inject取值
// HelloWorld.vue
<template>
<div class="">我是Hello World组件</div>
</template>
<script>
export default {
inject: ['name', 'age'], // 子代通过inject取出父辈注入的值
data() {
return {}
},
created() {
console.log(this.name, this.age); // "帅哥", 1
}
}
</script>
如果说我们需要通过provide 传递自身data里面的值时,这时候需要换成函数形式:
// App.vue
<template>
<div>
<h2>当前数为: {{count}}</h2>
</div>
</template>
<script>
import Child from './components/Child.vue'
export default {
provide() { // 如果需要传入data里的值,则不能使用对象写法,否则会报错。
return {
name: '帅哥',
age: this.count
}
},
name: 'App',
components: {
Child
},
data() {
return {
count: 520
}
},
}
</script>
但是这样仅仅只是传一次count的值,假如count的值被修改,传给子辈的值依然是原来的值,无法达到响应式,那么这个时候就要换一种写法:
// App.vue
<template>
<div>
<h2>当前数为: {{count}}</h2>
</div>
</template>
<script>
import Child from './components/Child.vue'
import { computed } from 'vue'
export default {
provide() { // 如果需要传入data里的值,则不能使用对象写法,否则会报错。
return {
name: '帅哥',
age: computed(() => this.count) // ref对象.value,子辈组件通过 age.value取值
}
},
name: 'App',
components: {
Child
},
data() {
return {
count: 520
}
},
}
</script>
总结:
组件之间通信包含: 父传子(props)、子传父($emit)、父传子辈(provide/inject),那么还有一个是跨组件通信的是 vuex,后面再做记录。