持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
一、前言
最近在学习vue3,对其中的setup稍微有点理解,整理记录一下。
二、setup
1、简单介绍
setup是vue3新提出的一个api函数,为什么会引入这个函数呢,因为vue2里,在每个vue文件,我们有data、computed、watch、methods等等选项API,在大多数情况下,我们能把项目理得井井有条,但是有这么一种情况,当页面需求越来越多,组件逻辑也变得越来越丰富的情况下,也就代码变得臃肿了起来,即使写了规范的注释,但我们的阅读和维护成本也会逐步提高,这种时候使用setup函数,就可以将其中一部分逻辑抽离出来,减少开发者应该关心的逻辑问题。
所以setup函数被定义为--- Composition API(组合API)的入口
2、身处的生命周期
我们都知道vue有以下生命周期,setup函数就处理beforeCreate和created之间,这个时候组件还没挂载,所以就用不了vue的data、methods的数据或者方法的,需要注意一下。vue3为了防止我们错误使用,在setup函数里也将this实例给干掉了,所以也用不了this。
beforeCreate(创建前)
created(创建后)
beforeMount(载入前)
mounted(载入后)
beforeUpdate(更新前)
updated(更新后)
beforeDestroy(销毁前)
3、两种模式
setup有两种模式,也就是两种写法,但不管是哪种写法,都会在启动页面后自动执行。 顺带一提,setup是同步的,不能是异步逻辑。
第一种是script标签包裹的内容里使用setup函数。
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
// export default { // 如果不是ts,那就直接用这个开头
setup () {
// 定义数据和函数
const msg = 'hi vue3'
const say = () => {
console.log(msg)
}
return { msg , say}
}
}
</script>
第二种是直接在script标签里直接加上setup来使用。
<script setup lang="ts">
</script>
4、setup函数
需要将定义的数据和函数都return出来,才能在组件实例里进行使用。
4.1 setup函数的形参---props
setup函数的形参,第一个参数,props是一个对象,包含了父组件传递给子组件所有的所有数据,在子组件中通过props属性配置进行接收,包含了配置并且声明的所有属性的对象。
举个例子:message是父组件A传给子组件B的一个属性值,那要在setup函数里运用到,需要以下写法。
props: {
message: String,
},
/**
* 如果不配置props
* 那么setup函数中拿到的这个属性则是undefined
*/
setup(props) {
console.log(props) // 打印结果
}
4.2 setup函数的形参---context
setup函数的形参,第二个参数,context是一个对象,里面包含了四个属性值:attrs、emit、expose、slot。
4.2.1 attrs
attrs:获取当前标签上的所有属性的对象,attrs是接收props没有声明的属性,如果子组件用props已经进行声明,那么子组件我们需要使用setup函数的props去接收,不能使用attrs。
同样我们举个例子,meg是父组件A传给子组件B的一个属性值,message我们在props里定义了
也就是这样的写法
props: {
message: String
},
setup (props, context) {
console.log(props, context)
}
我们看看结构,首先是props的,可以看到其中只有刚刚声明的message
然后是context的结构,这里只剩一个msg了,message如果在props里声明了,那就不会在attrs里出现了。
4.2.2 emit
emit:事件分发,应用于子传父,如果将子组件的数传递给父级就需要使用该方法。
开发过程中,我们经常会碰到,子组件修改父组件的传递过来的值,那势必得通知父组件进行修改,不能直接在子组件里把值给修改了。
我们先在父组件声明一个handlefunction函数,并且挂载到子组件上。
然后就可以在子组件的setup里读取到了,采用context.emit的方式,第一个参数是绑定的名字,第二个是参数
setup (props, context) {
console.log(props, context)
const handleClick = function () {
context.emit('handle', '子级数据传递')
}
return {
handleClick
}
}
4.2.3 expose
expose:expose 是早先 Vue RFC 中的一个提案,expose 的设想是提供一个像 expose({ ...publicMembers })
这样的组合式 API,这样组件的作者就可以在 setup() 中使用该 API 来清除地控制哪些内容会明确地公开暴露给组件使用者。感兴趣可以试试看哦。
还是用上述的组件,这次我们新增两个fun1、fun2函数,同时只用expose抛出其中handleClick和fun1函数,fun2函数我们不抛出,来看看父组件里的ref的机构。
setup (props, context) {
console.log(props, context)
const handleClick = function () {
context.emit('handle', '子级数据传递')
}
const fun1 = function () {
console.log('这是fun1')
}
const fun2 = function () {
console.log('这是fun2')
}
context.expose({
handleClick, fun1
})
return {
handleClick, fun1, fun2
}
}
父组件获取ref的方式和vue2对比,也有点小变化了,我父组件用的是**<script setup lang="ts"
**,
这里需要注意的是,变量名set,和ref绑定的一样。
import { ref,onMounted } from 'vue'
const set = ref(null)
onMounted(()=>{
// 当界面挂载出来后就会自动执行
console.log(set.value)
})
下面是获取到的ref结构,可以发现fun2并没有出现,原因就是使用expose之后,默认抛出的部分就是以expose为准,而不是return。
4.2.4 slot
slot:插槽,带有dom属性,如果想把一段html或者一个组件当作属性传入到子组件中就使用slots,接收父级传递下来的html内容。
父组件添加内容
<SET ref="set" msg="attrs用" message="sss" @handle="handlefunction">
<template v-slot:header>
测试插槽
</template>
</SET>
子组件使用内容 html部分直接用
<slot name="header"></slot>
或者在setup函数里直接使用context.slots.header(),返回的是一个数组。
console.log(props, context, context.slots.header())
因为我只定义了一个插槽,所以只返回了一个。
5、setup标签
5.1 获取props的方式
需要用到defineProps方法来接收父组件传来的prop值,defineProps方法不需要额外引入,直接使用即可。
const props = defineProps({
message: {
type: String,
default: '默认值',
require: true// 设置之后,props必须要接收到这个数据,默认为false
},
msg: {
type: String,
default: '默认值',
require: true// 设置之后,props必须要接收到这个数据,默认为false
}
})
5.2 如何使用context
目前我只知道这两个语法糖,defineEmits、defineExpose
这两个分别可以访问到context里的emit和expose属性
用defineEmits代替emit
const emit = defineEmits(['handle'])
const handleClick = function () {
emit('handle', '子级数据传递')
}
用defineExpose代替expose
const fun1 = function () {
console.log('这是fun1')
}
defineExpose({
fun1
})
三、小结
以上这些就是我对setup的相关理解了,可能不是特别全面,有错误的地方还请指正。
ps: 我是地霊殿__三無,一天卷一点。