props/defineProps
props通过在子组件上绑定属性来实现父子组件之间的数据传递。父组件将数据作为prop传递给子组件,子组件在自己的作用域中可以访问和使用这些prop。
用法
子组件
defineProps(["page"]);
defineProps({ page:Number });
defineProps({ page:{ type:Number, default:2 } });
defineProps:{ page:[String,Number] }
|
若想在子组件内使用,可以用一个const常量接收defineProps
的返回值,然后通过这个常量即可调用。
父组件
使用:
来传递值
示例
子组件
<template> <h1>子组件</h1> <ul class="list"> <li class="list-item" v-for="(item, index) in props.msg" :key="index"> {{ item }} </li> </ul> </template>
<script setup> const props = defineProps({ msg: { type: Array, default: () => [] } }) </script>
|
父组件
<template> <h1>父组件</h1> <div class="input-group"> <input type="text" v-model="val"> <button @click="handle">发送数据</button> </div> <Child :msg="list"/> </template>
<script setup> import { ref } from 'vue'; import Child from './components/Child1-1.vue'; const val = ref(""); const list = ref(['666']); const handle = () => { list.value.push(val.value); } </script>
|
效果
emits/defineEmits
emits通过在子组件中声明可触发的事件,使得子组件可以在适当的时机触发这些事件。父组件可以在子组件上监听这些事件,并在触发时执行相应的处理逻辑。
用法
父组件
使用@
传递方法以监听
子组件
首先声明一个变量emits
来接收父组件的方法,然后在子组件内需要触发父组件方法的函数内使用emits
即可。
const emits = defineEmits(['add']) const handle = () => { emits('add', val.value) }
|
<button @click="handle">发送数据</button>
|
示例
父组件
<template> <Child @add="handleAdd"/> <h1>父组件</h1> <ul class="list"> <li class="list-item" v-for="(item, index) in list" :key="index"> {{ item }} </li> </ul> </template>
<script setup> import { ref } from 'vue'; import Child from './components/Child2-1.vue'; const list = ref(['默认测试数据']) const handleAdd = (val) => { list.value.push(val); } </script>
|
子组件
<template> <h1>子组件</h1> <div class="input-group"> <input type="text" v-model="val"> <button @click="handle">发送数据</button> </div> </template>
<script setup> import { ref } from 'vue'; const val = ref(""); const emits = defineEmits(['add']) const handle = () => { emits('add', val.value) } </script>
|
效果
ref/defineExpose
通过使用ref
将数据或方法包装,并使用defineExpose
将其暴露给父组件。父组件可以通过在子组件上使用ref
来访问这些暴露出来的数据或方法。这种方式使得父组件可以直接访问和操作子组件的内部状态。
和defineProps
、defineEmits
一样,defineExpose
也是内置的,不需要import,不过defineProps
,defineEmits
都会返回一个实例,而defineExpose
是没有返回值的,而且要在方法声明定义以后使用。
用法
子组件
defineExpose({ 暴露给父组件的变量名:子组件内变量 })
|
父组件
首先使用ref包装子组件<Child ref="childRef"/>
,然后通过ref调用子组件暴露的变量即可。
示例
子组件
<template> <h1>子组件</h1> <div class="input-group"> <input type="text" v-model="val"> <button @click="handle">添加</button> </div> </template>
<script setup> import { ref } from 'vue'; const val = ref('') const list = ref(['默认测试数据!']) const handle = () => { list.value.push(val.value); } defineExpose({msg:list}) </script>
|
父组件
在template
内使用:
<template> <Child ref="childRef"/> <h1>父组件</h1> <ul class="list"> <li class="list-item" v-for="(item, index) in childRef?.msg" :key="index"> {{ item }} </li> </ul> </template>
<script setup> import { ref } from 'vue'; import Child from './components/Child4.vue'; const childRef = ref(""); </script>
|
childRef?.msg
这里的问号是等childRef
数据加载完毕后才去取数据,否则这里可能取不到值,这里需要考虑到父组件和子组件的生命周期。
在script内使用:
const formDialogRef = ref(AddressFormDialog)
const openDialog=(mode)=>{ if (!formDialogRef.value) return formDialogRef.value.openDialog(mode) }
|
v-model
v-model是通过将属性和事件绑定到同一个值来实现双向数据绑定。相当于父组件将自己的数据源交给子组件处理,父组件里不需要写什么代码,操作大都放到子组件里去写。
示例
父组件
<template> <Child v-model:msg="list"/> <h1>父组件</h1> <ul class="list"> <li class="list-item" v-for="(item, index) in list" :key="index"> {{ item }} </li> </ul> </template>
<script setup> import { ref } from 'vue'; import Child from './components/Child3.vue'; const list = ref(['默认测试数据!']) </script>
|
子组件
<template> <h1>子组件</h1> <div class="input-group"> <input type="text" v-model="val"> <button @click="handle">添加</button> </div> </template>
<script setup> import { ref } from 'vue'; const props = defineProps({ msg:Array }) const val = ref('') const emits = defineEmits(['update:msg']) const handle = () => { const arr = props.msg; arr.push(val.value); emits('update:msg', arr); } </script>
|
attrs
attrs用于子组件接收父组件中不是通过props接收的属性。父组件给子组件传递属性,可以是自定义属性,这对于在子组件中将额外的prop传递给子元素或子组件比较有用。
示例
父组件
<template> <h1>父组件 传送数据</h1> <Child :fruit="data1" :type="data2"/> </template>
<script setup> import { ref } from 'vue'; import Child from './components/Child6.vue'; const data1 = ref("水果"); const data2 = ref("哈密瓜"); </script>
|
子组件
<template> <h1>子组件 接收数据</h1> <p>子组件通过props收到的是: {{props.fruit}}</p> <p>子组件通过attrs收到的是: {{attrs.type}}</p> </template>
<script setup> import { useAttrs } from 'vue'; const props = defineProps({ fruit: { type: String, default: "" } }) const attrs = useAttrs(); console.log(attrs); </script>
|
效果
参考链接
vue3中父子传值 defineProps和defineEmits用法 - 掘金 (juejin.cn)
Vue父子组件通信的6种方式,props、emits、defineExpose、provide、attrs… - 掘金 (juejin.cn)
[Vue3] defineExpose用法 - 掘金 (juejin.cn)
Rean's Blog
Enjoy technology and music