vue3 组件通讯
父子通讯
父传子
- 父组件向子组件传递数据:自定义属性 props
- 子组件向父组件传递数据 : 自定义事件 $emit()
- 子组件模板中直接可以获取props中的属性值
- js代码中需要通过setup函数的第一个形参props获取属性值
父组件:
<template>
<div>
<div>父子组件的交互</div>
<button @click='money=200'>修改</button>
<hr>
<Child :money='money' />
</div>
</template>
<script>
import Child from './Child.vue'
import { ref } from 'vue'
export default {
name: 'App',
components: { Child },
setup () {
const money = ref(100)
return { money }
}
}
</script>
子组件:
<template>
<div>
子组件 {{money}}
</div>
<button @click='getMoney'>点击</button>
</template>
<script>
export default {
name: 'Child',
props: {
money: {
type: Number,
default: 0
}
},
setup (props) {
// Vue3中,使用形参props获取所有父组件传递的数据
// props的数据是只读的,不可以在子组件直接修改
const getMoney = () => {
console.log(props.money)
}
return { getMoney }
}
}
</script>
子传父
- 通过setup函数的参数二context.emit方法触发自定义事件
context.emit('send-money', 50)
- 子组件触发的自定义事件需要在emits选项中进行声明(直观的看到本组件触发了那些自定义事件)
父组件:
<template>
<div>
<div>父子组件的交互</div>
<button @click='money=200'>修改</button>
<hr>
+ <Child :money='money' @send-money='getMoney' />
</div>
</template>
<script>
import Child from './Child.vue'
import { ref } from 'vue'
export default {
name: 'App',
components: { Child },
setup () {
const money = ref(100)
+ const getMoney = (value) => {
+ // value就是子组件传递回来的钱
+ money.value = money.value - value
+ }
+ return { money, getMoney }
}
}
</script>
子组件:
<template>
<div>
子组件 {{money}}
</div>
<button @click='getMoney'>点击</button>
</template>
<script>
export default {
name: 'Child',
+ // 子组件触发的自定义事件需要在emits选项中进行声明(直观的看到本组件触发了那些自定义事件)
+ emits: ['send-money'],
props: {
money: {
type: Number,
default: 0
}
},
setup (props, context) {
// Vue3中,使用形参props获取所有父组件传递的数据
// props的数据是只读的,不可以在子组件直接修改
const getMoney = () => {
console.log(props.money)
// this.$emit('send-money', 50)
// 向父组件传递数据50
+ context.emit('send-money', 50)
}
return { getMoney }
}
}
</script>
后代元素的传值 依赖注入 provide inject
使用场景:有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据。
父向后代传值
- 父传子孙数据:provide
- 子孙得到数据:inject
父组件:
<template>
<div>
<div>父子组件的交互</div>
<button @click='money=200'>修改</button>
<hr>
<Child :money='money' @send-money='getMoney' />
</div>
</template>
<script>
import Child from './Child.vue'
+ import { ref, provide } from 'vue'
export default {
name: 'App',
components: { Child },
setup () {
+ // 直接把数据传递出去
+ provide('moneyInfo', 1000)
const money = ref(100)
const getMoney = (value) => {
// value就是子组件传递回来的钱
money.value = money.value - value
}
return { money, getMoney }
}
}
</script>
孙组件:
<template>
<div>
+ 孙子组件:{{moneyInfo}}
</div>
</template>
<script>
+ import { inject } from 'vue'
export default {
name: 'GrandSon',
setup () {
+ const moneyInfo = inject('moneyInfo')
+ return { moneyInfo }
}
}
</script>
子组件:
<template>
<div>
+ 子组件 {{money}} --- {{moneyInfo}}
</div>
<button @click='getMoney'>点击</button>
<GrandSon />
</template>
<script>
import GrandSon from '@/GrandSon'
import { inject } from 'vue'
export default {
name: 'Child',
components: { GrandSon },
// 子组件触发的自定义事件需要在emits选项中进行声明(直观的看到本组件触发了那些自定义事件)
emits: ['send-money'],
props: {
money: {
type: Number,
default: 0
}
},
setup (props, context) {
+ const moneyInfo = inject('moneyInfo')
// Vue3中,使用形参props获取所有父组件传递的数据
// props的数据是只读的,不可以在子组件直接修改
const getMoney = () => {
console.log(props.money)
// this.$emit('send-money', 50)
// 向父组件传递数据50
context.emit('send-money', 50)
}
+ return { getMoney, moneyInfo }
}
}
</script>
后代向父(祖先传值)
子组件传递数据给爷爷组件,需要通过provide一个函数的方式实现
- 爷爷组件传递一个函数,后续通过函数的形参获取数据
- 孙子组获取并调用该函数传递数据
父组件:
<template>
<div>
<div>父子组件的交互</div>
<button @click='money=200'>修改</button>
<hr>
<Child :money='money' @send-money='getMoney' />
</div>
</template>
<script>
import Child from './Child.vue'
import { ref, provide } from 'vue'
export default {
name: 'App',
components: { Child },
setup () {
// 直接把数据传递出去
provide('moneyInfo', 1000)
// 把一个函数传递给孙子
+ const handleMoney = (value) => {
+ console.log('孙子传递的数据:', value)
+ }
+ provide('handleMoney', handleMoney)
const money = ref(100)
const getMoney = (value) => {
// value就是子组件传递回来的钱
money.value = money.value - value
}
return { money, getMoney }
}
}
</script>
孙子组件:
<template>
<div>
孙子组件:{{moneyInfo}}
</div>
+ <button @click='handleSend'>点击给爷爷数据</button>
</template>
<script>
import { inject } from 'vue'
export default {
name: 'GrandSon',
setup () {
const moneyInfo = inject('moneyInfo')
+ const handleMoney = inject('handleMoney')
+ const handleSend = () => {
+ // 调用爷爷传递函数
+ handleMoney(200)
+ }
return { moneyInfo, handleSend }
}
}
</script>
vue3中的v-model
取代了.sync修饰符
- Vue2的规则
- Vue2中v-model默认绑定的属性是value
- Vue2中v-model默认绑定的事件是@input
- Vue3的规则
- Vue3中v-model默认绑定的属性是modelValue
- Vue3中v-model默认绑定的事件是@update:modelValue
父组件:
<template>
<div>
<div>v-model指令用法-Vue3</div>
<hr>
<div>{{info}}</div>
<div>{{msg}}</div>
<!-- v-model提供了一种双向绑定机制(在组件上-父子之间的数据交互) -->
<!-- .sync修饰符已经被废弃,替代方案是v-model -->
<!-- <TestEvent v-model='info' :msg.sync='msg' /> -->
<TestEvent v-model:modelValue='info' v-model:msg='msg' />
<!-- <TestEvent :modelValue='info' @update:modelValue='info=$event' /> -->
</div>
</template>
<script>
import TestEvent from './TextEvent.vue'
import { ref } from 'vue'
export default {
name: 'App',
components: { TestEvent },
setup () {
const info = ref('hello')
const msg = ref('hi')
return { info, msg }
}
}
</script>
子组件:
<template>
<div>
子组件 {{modelValue}}
</div>
<button @click='handleEdit'>点击</button>
</template>
<script>
export default {
name: 'TestEvent',
props: {
// Vue3中,v-model默认绑定的属性名称是modelValue
modelValue: {
type: String,
default: ''
},
msg: {
type: String,
default: ''
}
},
setup (props, context) {
const handleEdit = () => {
// props.modelValue = 'nihao'
// 通知父组件修改数据
// .sync修饰符:update:绑定的属性名称
context.emit('update:modelValue', 'nihao')
context.emit('update:msg', 'coniqiwa')
}
return { handleEdit }
}
}
</script>