vue3中的组件通信【1】《父子组件通信》
文章目录
- 父子组件通信
- (1)props / emits
- ①props
- 使用props
- 获取非 Prop 的 Attribute
- emits(子传父)
- (2)v-model / emits
- (3)ref / emits
父子组件通信

(1)props / emits
①props
Father.vue
<template><Childtitle="用户信息":index="1":uid="userInfo.id":user-name="userInfo.name"/>
</template><script>
import { defineComponent } from 'vue'
import Child from '@cp/Child.vue'interface Member {id: number,name: string
};export default defineComponent({// 需要启用子组件作为模板components: {Child},// 定义一些数据并return给template用setup () {const userInfo: Member = {id: 1,name: 'Petter'}// 不要忘记return,否则template拿不到数据return {userInfo}}
})
</script>
Child.vue
export default defineComponent({props: ['title','index','userName','uid']
})
加上类型限制:
export default defineComponent({props: {title: String,index: Number,userName: String,uid: Number}
})

如果你需要对某个 prop 允许多类型,比如这个 uid 字段,它可能是数值,也可能是字符串,那么可以在类型这里,使用一个数组,把允许的类型都加进去。
export default defineComponent({props: {// 单类型title: String,index: Number,userName: String,// 这里使用了多种类型uid: [ Number, String ]}
})
对部分字段设置为可选,并提供默认值:
export default defineComponent({props: {// 可选,并提供默认值title: {type: String,required: false,default: '默认标题'},// 默认可选,单类型index: Number,// 添加一些自定义校验userName: {type: String,// 在这里校验用户名必须至少3个字validator: v => v.length >= 3},// 默认可选,但允许多种类型uid: [ Number, String ]}
})

使用props
template 部分
<template><p>标题:{{ title }}</p><p>索引:{{ index }}</p><p>用户id:{{ uid }}</p><p>用户名:{{ userName }}</p>
</template>
script 部分
export default defineComponent({props: {title: String,index: Number,userName: String,uid: Number},// 在这里需要添加一个入参setup (props) {// 该入参包含了我们定义的所有propsconsole.log(props);}
})
获取非 Prop 的 Attribute
在 Child.vue 里,可以通过 setup 的第二个参数 context 里的 attrs 来获取到这些属性。
export default defineComponent({setup (props, { attrs }) {// attrs 是个对象,每个 Attribute 都是它的 keyconsole.log(attrs.class);// 如果传下来的 Attribute 带有短横线,需要通过这种方式获取console.log(attrs['data-hash']);}
})
emits(子传父)
Child.vue 绑定一个更新用户年龄的方法,那么在 Father.vue 里需要这么处理:
<template><Child@update-age="updateAge"/>
</template>
<script>
import { defineComponent, reactive } from 'vue'
import Child from '@cp/Child.vue'interface Member {id: number,name: string,age: number
};export default defineComponent({components: {Child},setup () {const userInfo: Member = reactive({id: 1,name: 'Petter',age: 0})// 定义一个更新年龄的方法const updateAge = (age: number): void => {userInfo.age = age;}return {userInfo,// return给template用updateAge}}
})
</script>
动态绑定 props 是用 :,绑定 emit 是用 @
Child.vue
export default defineComponent({emits: ['update-age']
})
接收 emits 时做一些校验
比如上面的更新年龄,只允许达到成年人的年龄才会去更新父组件的数据:
export default defineComponent({emits: {// 需要校验'update-age': (age: number) => {// 写一些条件拦截,记得返回falseif ( age < 18 ) {console.log('未成年人不允许参与');return false;}// 通过则返回truereturn true;},// 一些无需校验的,设置为null即可'update-name': null}
})
调用 emits
export default defineComponent({emits: ['update-age'],setup (props, { emit }) {// 2s 后更新年龄setTimeout( () => {emit('update-age', 22);}, 2000);}
})
(2)v-model / emits
- 在 Father.vue ,通过 v-model 向 Child.vue 传值
- Child.vue 通过自身设定的 emits 向 Father.vue 通知数据更新
Father.vue
<template><Childv-model:user-name="userInfo.name"/>
</template>
如果你要绑定多个数据,写多个 v-model 即可
<template><Childv-model:user-name="userInfo.name"v-model:uid="userInfo.id"/>
</template>
看到这里应该能明白了,一个 v-model 其实就是一个 prop,它支持的数据类型,和 prop 是一样的。
所以,子组件在接收数据的时候,完全按照 props 去定义就可以了。
export default defineComponent({props: ['title','index','userName','uid']
})
Child.vue
虽然 v-model 的配置和 prop 相似,但是为什么出这么两个相似的东西?自然是为了简化一些开发上的操作。
使用 props / emits,如果要更新父组件的数据,还需要在父组件定义好方法,然后 return 给 template 去绑定事件给子组件,才能够更新。
而使用 v-model / emits ,无需如此,可以在 Child.vue 直接通过 “update:属性名” 的格式,直接定义一个更新事件:
export default defineComponent({props: {userName: String,uid: Number},emits: ['update:userName','update:uid']
})
调用自身的 emits
在 Child.vue 配置好 emits 之后,就可以在 setup 里直接操作数据的更新了:
export default defineComponent({// ...setup (props, { emit }) {// 2s 后更新用户名setTimeout(() => {emit('update:userName', 'Tom')}, 2000);}
})
(3)ref / emits
在学习 响应式 API 之 ref 的时候,我们了解到 ref 是可以用在 DOM 元素与子组件 上面。
所以,父组件也可以直接通过对子组件绑定 ref 属性,然后通过 ref 变量去操作子组件的数据或者调用里面的方法。
比如导入了一个 Child.vue 作为子组件,需要在 template 处给子组件标签绑定 ref:
<template><Child ref="child" />
</template>
然后在 script 部分定义好对应的变量名称(记得要 return 出来):
import { defineComponent, onMounted, ref } from 'vue'
import Child from '@cp/Child.vue'export default defineComponent({components: {Child},setup () {// 给子组件定义一个ref变量const child = ref<HTMLElement>(null);// 请保证视图渲染完毕后再执行操作onMounted( () => {// 执行子组件里面的ajax函数child.value.getList();// 打开子组件里面的弹窗child.value.isShowDialog = true;});// 必须return出去才可以给到template使用return {child}}
})
子组件如果想主动向父组件通讯,也需要使用 emit
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
