后面会用到的知识点(补充)
后缀运算符
在Vue 3中,有两个后缀运算符:?和!,分别表示可选属性和非空断言。
?可选属性:表示该属性是可选的,如果该属性不存在,不会引发错误。
const message = { text: 'Hello World' }
const greeting = message.text?.toUpperCase() // greeting = 'HELLO WORLD'
const emptyMessage = {}
const emptyGreeting = emptyMessage.text?.toUpperCase() // emptyGreeting = undefined
在上面的代码中,当message对象存在text属性时,可以将text属性的值转换为大写字母。而当emptyMessage对象不存在text属性时,使用?.运算符访问text属性不会引发错误,返回值为undefined。
!非空断言:表示该属性一定存在,如果该属性不存在,则会引发错误。
const message = { text: 'Hello World' }
const greeting = message.text!.toUpperCase() // greeting = 'HELLO WORLD'
const emptyMessage = {}
const emptyGreeting = emptyMessage.text!.toUpperCase() // TypeError: Cannot read property 'toUpperCase' of undefined
在上面的代码中,当message对象存在text属性时,可以将text属性的值转换为大写字母。而当emptyMessage对象不存在text属性时,使用!运算符访问text属性会引发错误,因为该属性不存在。
在vue中,子父组件传参一直都是非常重要的
父组件向子组件传参(父---->子)
父组件通过 :传参名=“传递的数据” 向子组件传递参数
子组件通过 defineProps<{接收的数据}>() 来接收数据
在 script setup 中,引入的组件会自动注册,所以可以直接使用,无需再通过components进行注册
父组件
<template>
<div>父组件数据</div>
<br>
<div>姓名:{{ data.name }}</div>
<br>
<div>年龄:{{ data.age }}</div>
<br>
<div>================================</div>
<br>
// 在 script setup 中,引入的组件会自动注册,所以可以直接使用,无需再通过components进行注册
<Child :name="data.name" :age="data.age"></Child>
</template>
<script setup lang="ts">
// 引入子组件
import Child from './Child.vue'
// 引入方法
import {reactive} from 'vue'
const data = reactive({
name: '大哥',
age:20
})
</script>
子组件
方法一:
<template>
<div>子组件数据</div>
<br>
<div>姓名:{{ name }}</div>
<br>
<div>年龄:{{ age }}</div>
<br>
</template>
<script setup lang="ts">
// 接收数据,(写法一)
defineProps<{
name: string,
age:number
}>()
// 接收数据, (写法二)
defineProps({
name: string,
age:number
})
注意:在script中使用接收的数据,要先接收;template中不用
const props = defineProps({
name: string,
age:number
})
</script>
方法二:
<template>
<div>子组件数据</div>
<br>
<div>姓名:{{ name }}</div>
<br>
<div>年龄:{{ age }}</div>
<br>
</template>
<script setup lang="ts">
// 接收数据
// defineProps<{
// name: string,
// age:number
// }>()
// 定义接收数据的类型
type Props = {
name?: string,
age?: number
data?:Object
}
// 使用 withDefaults 定义默认值
withDefaults(defineProps<Props>(), {
name:'二弟',
age: 10,
})
</script>
结果:
注入式父子组件传参
父组件可以向子组件(无论层级)注入依赖,每个子组件都可以获得这个依赖,无论层级。
父组件
<script setup>
import child1 from "./child.vue";
import {reactive} from 'vue'
provide() {
return { parentData: data.msg };
},
const data = reactive({
msg: "我是父组件的数据",
})
</script>
子组件
<template>
<p>我是子组件</p>
<p>parent组件数据:{{parentData}}</p>
</template>
<script setup>
inject: ["parentData"],
mounted() {
console.log('父辈组件的数据',parentData)
},
</script>
子组件向父组件传参(子---->父)
在Vue 3中,可以使用
defineEmits函数来声明子组件可以触发的事件。该函数需要在子组件中使用,并且需要在setup函数中调用
子组件
<template>
<div>子组件数据</div>
<br>
<button @click="changeMsg">向父组件传参</button>
<br>
<div>姓名:{{ name }}</div>
<br>
<div>年龄:{{ age }}</div>
<br>
</template>
<script lang="ts" setup>
import { onMounted } from "vue";
import { ref } from "vue";
const sex = ref('男')
// defineEmits 函数来声明子组件可以触发的事件
// 语法:const 事件名 = defineEmits(['事件'])
const emits = defineEmits(['changeMsg'])
// 点击事件changeMsg
const changeMsg = () => {
// 用注册好的事件,向父组件传参
// 语法:声明的事件名('事件',递的数据)
emits('changeMsg',sex)
}
</script>
父组件
<template>
<div>父组件数据</div>
<br>
<div>姓名:{{ data.name }}</div>
<br>
<div>年龄:{{ data.age }}</div>
<br>
<div>年龄:{{ data.sex }}</div>
<br>
<div>================================</div>
<br>
<Child :name="data.name" :age="data.age" @changeMsg="changeMsg"></Child>
</template>
<script setup lang="ts">
import Child from './Child.vue'
import {reactive} from 'vue'
const data = reactive({
name: '大哥',
age: 20,
sex:''
})
// 形参要有数据类型
const changeMsg = (message: string) => {
data.sex = message
}
</script>
结果:
defineExpose 获取子组件的实例和内部属性
在vue2中,通常会在子组件便签上加,
ref来获取子组件的实例和属性方法,在 Vue3的script-setup 模式下,所有数据只是默认 return 给 template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载 ref 变量获取子组件的数据。如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,
defineExpose可以实现
子组件
<template>
<p>{{name}}</p>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const name = ref('张麻子')
const changeName = () => {
name.value = '县长'
}
// 将方法、变量暴露给父组件使用,父组件才可通过 ref API拿到子组件暴露的数据
defineExpose({
name,
changeName
})
</script>
父组件
<template>
<div>
<child ref='childRef' />
<button @click="getName">获取子组件中的数据</button>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import child from './Child.vue'
// 子组件ref(TypeScript语法)
const childRef = ref(null)
const getName = () => {
// 获取子组件name
console.log(childRef.value!.name)
// 执行子组件方法
childRef.value?.changeName()
// 获取修改后的name
console.log(childRef.value!.name)
}
</script>