defineProps、defineEmits、defineExpose组件通信
在使用这个之前,我们需要知道setup的语法糖写法,因为上面的三个api需要在这个语法糖中才能使用:
<script setup>
console.log('LiuQing')
</script>
里面的代码会被编译成组件 setup() 函数的内容。
这意味着与普通的 <script> 只在组件被首次引入的时候执行一次不同,<script setup> 中的代码会在每次组件实例被创建的时候执行。
官方解释:
<script setup>
是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐。
相比于普通的 <script> 语法,它具有更多优势:
1、更少的样板内容,更简洁的代码。
2、能够使用纯 TypeScript 声明 props 和自定义事件。
3、更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
4、更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。
顶层的绑定会被暴露给模板:
<template>
name: {{ name }} <br />
age: {{ age }}
</template>
<script setup>
import { ref } from 'vue'
const name = ref('LiuQing')
const age = ref(18)
</script>
页面:
不需要主动暴露return。
使用组件:
<template>
name: {{ name }} <br />
age: {{ age }}
<Children2/>
</template>
<script setup>
import Children2 from './components/Parent/Children2.vue'
import { ref } from 'vue'
const name = ref('LiuQing')
const age = ref(18)
</script>
子组件:
<template>我是子组件哦</template>
页面:
defineProps、defineEmits、defineExpose这三个api我们可以直接使用并不需要在vue中单独暴露出来
defineProps
<template>
我是子组件哦
<p>子组件得到的name:{{ props.name }}</p>
<p>子组件得到的age:{{ props.age }}</p>
</template>
<script setup>
import { defineProps, defineEmits, defineExpose } from 'vue'
const props = defineProps({
name: {
type: String,
default: "六卿",
},
age: {
type: Number,
default: 279
}
})
</script>
其实我们使用的时候完全可以不导入。
目前页面:
因为我们目前还没有给子组件传入name、age,所以使用的默认值。
在父组件传入name、age:
<template>
name: {{ name }} <br />
age: {{ age }}
<Children2 :name="name" :age="age" />
</template>
<script setup>
import Children2 from './components/Parent/Children2.vue'
import { ref } from 'vue'
const name = ref('LiuQing')
const age = ref(18)
</script>
写法完全和v2一致,使用v-bind或者:即可达到效果。
当前页面:
已经收到了传入的值。
defineEmits
defineProps为了解决子组件接受父组件传入的值,那defineEmits就是子组件给父组件传值,当然这个传值是以回调函数的形式传送。
使用的前提是需要父组件传入回调函数,子组件使用defineEmits接受,触发事件。
<template>
name: {{ name }} <br />
age: {{ age }}
<Children2 :name="name" :age="age" @changeName="changeName" />
</template>
<script setup>
import Children2 from './components/Parent/Children2.vue'
import { ref } from 'vue'
const name = ref('LiuQing')
const age = ref(18)
const changeName = (newName) => {
name.value = newName
}
</script>
子组件使用:
<template>
我是子组件哦
<p>子组件得到的name:{{ props.name }}</p>
<p>子组件得到的age:{{ props.age }}</p>
<button @click="changeName('六卿')">改变name为六卿</button>
</template>
<script setup>
import { defineProps, defineEmits, defineExpose } from 'vue'
const props = defineProps({
name: {
type: String,
default: "六卿",
},
age: {
type: Number,
default: 279
}
})
const emits = defineEmits(['changeName'])
const changeName = (name) => {
console.log("改变name")
emits('changeName', name)
}
</script>
页面:
点击后页面:
defineExpose
用于父组件要使用子组件中的方法或者属性的时候,子组件暴露给父组件,父组件配合ref使用:
子组件:
<template>
我是子组件哦
<p>子组件得到的name:{{ props.name }}</p>
<p>子组件得到的age:{{ props.age }}</p>
<button @click="changeName('六卿')">改变name为六卿</button>
------------------------------------------<br />
count :{{ count }}
</template>
<script setup>
import { defineProps, defineEmits, defineExpose, ref } from 'vue'
const props = defineProps({
name: {
type: String,
default: "六卿",
},
age: {
type: Number,
default: 279
}
})
const emits = defineEmits(['changeName'])
const changeName = (name) => {
console.log("改变name")
emits('changeName', name)
}
const count = ref(100)
const changeCount = () => {
count.value = --count.value
}
defineExpose({
count,
changeCount
})
</script>
父组件:
<template>
<button @click="changeCount">父组件按钮__改变count的值</button>
name: {{ name }} <br />
age: {{ age }}
<Children2 ref="child" :name="name" :age="age" @changeName="changeName" />
</template>
<script setup>
import Children2 from './components/Parent/Children2.vue'
import { ref } from 'vue'
const name = ref('LiuQing')
const age = ref(18)
const changeName = (newName) => {
name.value = newName
}
const child = ref(null)
const changeCount = () => {
console.log(child.value.count, 'child.value.count')
console.log(child.value.changeCount, 'child.value.changeCount')
child.value.changeCount()
}
</script>
页面:
子组件暴露,父组件ref接受。