script setup 语法糖
组合式 API:setup()
基本运用
Vue 3 的 Composition API 系列里,推出了一个全新的setup
函数,它是一个组件选项,在创立组件之前履行,一旦 props 被解析,并作为组合式 API 的进口点。
setup
选项是一个接纳props
和context
的函数,咱们参阅文档进行讨论。此外,咱们将setup
回来的一切内容都露出给组件的其余部分 (核算特点、办法、生命周期钩子等等) 以及组件的模板。
<script>
// 这是一个根据 TypeScript 的 Vue 组件
import { defineComponent } from 'vue'
export default defineComponent({
setup(props, context) {
// 在这里声明数据,或许编写函数并在这里履行它
return {
// 需求给 `<template />` 用的数据或函数,在这里 `return` 出去
}
},
})
</script>
新的setup
选项是在组件创立之前,props
被解析之后履行,是组合式 API 的进口。
留意:
在setup
中你应该避免运用this
,由于它不会找到组件实例。setup
的调用发生在data
property、computed
property 或methods
被解析之前,所以它们无法>在setup
中被获取。
在添加了setup的script标签中,咱们不必声明和办法,这种写法会主动将一切尖端变量、函数,均会主动露出给模板(template)运用
这里强调一句 “露出给模板,跟露出给外部不是一回事”
TIP:
说的浅显一点,便是在运用 Vue 3 生命周期的状况下,整个组件相关的业务代码,都能够放在setup
里履行。
由于在setup
之后,其他的生命周期才会被启用,咱们对比一下Vue2的Vue3生命周期的变化
组件生命周期
关于 Vue 生命周期的变化,能够从下表直观地了解:
Vue 2 生命周期 | Vue 3 生命周期 | 履行时间阐明 |
---|---|---|
beforeCreate | setup | 组件创立前履行 |
created | setup | 组件创立后履行 |
beforeMount | onBeforeMount | 组件挂载到节点上之前履行 |
mounted | onMounted | 组件挂载完结后履行 |
beforeUpdate | onBeforeUpdate | 组件更新之前履行 |
updated | onUpdated | 组件更新完结之后履行 |
beforeDestroy | onBeforeUnmount | 组件卸载之前履行 |
destroyed | onUnmounted | 组件卸载完结后履行 |
errorCaptured | onErrorCaptured | 当捕获一个来自子孙组件的反常时激活钩子函数 |
能够看到 Vue 2 生命周期里的beforeCreate
和created
,在 Vue 3 里已被setup
替代。
script setup 语法糖
它是 Vue3 的一个新语法糖,在 setup
函数中。一切 ES 模块导出都被认为是露出给上下文的值,并包括在 setup() 回来目标中。相对于之前的写法,运用后,语法也变得更简略。
主动注册特点和办法无需回来,直接运用
1.<script setup>
语法糖并不是新增的功能模块,它只是简化了以往的组合API(compositionApi)的必须回来(return)的写法,而且有更好的运行时性能。
2.在 setup 函数中:一切 ES 模块导出都被认为是露出给上下文的值,并包括在 setup() 回来目标中。相对于之前的写法,运用后,语法也变得更简略。
你不必担心setup语法糖的学习本钱,他是组合式API的简化,并没有新增的知识点。你只需求了解一些用法和细微的不同之处,乃至比之前写setup()还要顺手!
运用办法也很简略,只需求在 script 标签加上 setup 关键字即可
<script setup>
</script>
组件核心 API 的运用
组件主动注册
在 script setup 中,引进的组件能够直接运用,无需再经过components进行注册,而且无法指定当时组件的姓名,它会主动以文件名为主,也便是不必再写name特点了。
示例:
<template>
<Child />
</template>
<script setup>
import Child from '@/components/Child.vue'
</script>
界说组件的 props
defineProps —-> [用来接纳父组件传来的 props]代码示列
:
经过defineProps
指定当时 props 类型,获得上下文的props目标。
示例:
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
title: String,
})
</script>
<!-- 或许 -->
<script setup lang="ts">
import { ref,defineProps } from 'vue';
type Props={
msg:string
}
defineProps<Props>();
</script>
界说 emit
defineEmit —-> [子组件向父组件事情传递]
运用defineEmit
界说当时组件含有的事情,并经过回来的上下文去履行 emit。
代码示列:
<script setup>
import { defineEmits } from 'vue'
const emit = defineEmits(['change', 'delete'])
</script>
父子组件通信
defineProps用来接纳父组件传来的 props ;defineEmits用来声明触发的事情。
//父组件
<template>
<Child @getChild="getChild" :title="msg" />
</template>
<script setup>
import { ref } from 'vue'
import Child from '@/components/Child.vue'
const msg = ref('parent value')
const getChild = (e) => {
// 接纳父组件传递过来的数据
console.log(e); // child value
}
</script>
//子组件
<template>
<div @click="toEmits">Child Components</div>
</template>
<script setup>
// defineEmits,defineProps无需导入,直接运用
const emits = defineEmits(['getChild']);
const props = defineProps({
title: {
type: String,
defaule: 'defaule title'
}
});
const toEmits = () => {
emits('getChild', 'child value') // 向父组件传递数据
}
// 获取父组件传递过来的数据
console.log(props.title); // parent value
</script>
子组件经过 defineProps 接纳父组件传过来的数据,子组件经过 defineEmits 界说事情发送信息给父组件
useSlots()
和useAttrs()
获取 slots 和 attrs
注:useContext API 被弃用,取而代之的是更加细分的 api。
能够经过useContext
从上下文中获取 slots 和 attrs。不过提案在正式经往后,废除了这个语法,被拆分成了useAttrs
和useSlots
。
-
useAttrs
:见名知意,这是用来获取 attrs 数据,可是这和 vue2 不同,里边包括了class
、特点
、办法
。
<template>
<component v-bind='attrs'></component>
</template>
<srcipt setup lang='ts'>
const attrs = useAttrs();
<script>
-
useSlots
: 望文生义,获取插槽数据。
运用示例:
// 旧
<script setup>
import { useContext } from 'vue'
const { slots, attrs } = useContext()
</script>
// 新
<script setup>
import { useAttrs, useSlots } from 'vue'
const attrs = useAttrs()
const slots = useSlots()
</script>
defineExpose API
defineExpose —-> [组件露出出自己的特点]
传统的写法,咱们能够在父组件中,经过 ref 实例的办法去拜访子组件的内容,但在 script setup 中,该办法就不能用了,setup 相当所以一个闭包,除了内部的 template
模板,谁都不能拜访内部的数据和办法。
<script setup>
的组件默认不会对外部露出任何内部声明的特点。
假如有部分特点要露出出去,能够运用defineExpose
留意:现在发现
defineExpose
露出出去的特点以及办法都是unknown
类型,假如有修正类型的办法,欢迎评论区补充。
假如需求对外露出 setup 中的数据和办法,需求运用 defineExpose API。示例:
//子组件
<template>
{{msg}}
</template>
<script setup>
import { ref } from 'vue'
let msg = ref("Child Components");
let num = ref(123);
// defineExpose无需导入,直接运用
defineExpose({
msg,
num
});
</script>
//父组件
<template>
<Child ref="child" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Child from '@/components/Child.vue'
let child = ref(null);
onMounted(() => {
console.log(child.value.msg); // Child Components
console.log(child.value.num); // 123
})
</script>
界说响应变量、函数、监听、核算特点computed
<script setup >
import { ref,computed,watchEffect } from 'vue';
const count = ref(0); //不必 return ,直接在 templete 中运用
const addCount=()=>{ //界说函数,运用同上
count.value++;
}
//创立一个只读的核算特点 ref:
const plusOne = computed(() => count.value + 1)
// 创立一个可写的核算特点 ref
const plusOne = computed({
get: () => count.value + 1,
set: (val) => { count.value = val - 1 }
})
//界说监听,运用同上 //...some code else
watchEffect(()=>console.log(count.value));
</script>
watchEffect和watch区别
1、watch是惰性履行,也便是只有监听的值发生变化的时候才会履行,可是watchEffect不同,每次代码加载watchEffect都会履行(疏忽watch第三个参数的装备,假如修正装备项也能够实现立即履行)
2、watch需求传递监听的目标,watchEffect不需求
3、watch只能监听响应式数据:ref界说的特点和reactive界说的目标,假如直接监听reactive界说目标中的特点是不允许的,除非运用函数转换一下
4、watchEffect假如监听reactive界说的目标是不起作用的,只能监听目标中的特点。
reactive
回来一个目标的响应式署理。
<script setup>
import { reactive, onUnmounted } from 'vue'
const state = reactive({
counter: 0
})
// 定时器 每秒都会更新数据
const timer = setInterval(() => {
state.counter++
}, 1000);
onUnmounted(() => {
clearInterval(timer);
})
</script>
<template>
<div>{{state.counter}}</div>
</template>
运用ref也能到达咱们预期的’counter’,而且在模板中,vue进行了处理,咱们能够直接运用counter而不必写counter.value.
ref和reactive的联系:
ref是一个{value:’xxxx’}的结构,value是一个reactive目标
ref 露出变量到模板
曾经的提案中,假如需求露出变量到模板,需求在变量前参加export声明:
export const count = ref(0)
不过在新版的提案中,无需export声明,编译器会主动寻觅模板中运用的变量,只需像下面这样简略的声明,即可在模板中运用该变量
<script setup >
import { ref } from 'vue'
const counter = ref(0);//不必 return ,直接在 templete 中运用
const timer = setInterval(() => {
counter.value++
}, 1000)
onUnmounted(() => {
clearInterval(timer);
})
</script>
<template>
<div>{{counter}}</div>
</template>
其他 Hook Api
-
useCSSModule
:CSS Modules 是一种 CSS 的模块化和组合系统。vue-loader 集成 CSS Modules,能够作为模仿 scoped CSS。允许在单个文件组件的setup
中拜访CSS模块。此 api 本人用的比较少,不过多做介绍。 -
useCssVars
: 此 api 暂时材料比较少。介绍v-bind in styles
时提到过。 -
useTransitionState
: 此 api 暂时材料比较少。 -
useSSRContext
: 此 api 暂时材料比较少。
支持 async await 异步
留意在vue3的源代码中,setup履行结束,函数 getCurrentInstance 内部的有个值会释放对 currentInstance 的引证,await 句子会导致后续代码进入异步履行的状况。所以上述例子中最后一个 getCurrentInstance() 会回来 null,建议运用变量保存第一个 getCurrentInstance() 回来的引证.
<script setup>
const post = await fetch(`/api/post/1`).then((r) => r.json())
</script>
<script setup>
中能够运用顶层await
。结果代码会被编译成async setup()
:
<script setup>
const post = await fetch(`/api/post/1`).then(r => r.json())
</script>
另外,await 的表达式会主动编译成在await
之后保留当时组件实例上下文的格式。
留意
async setup()
必须与Suspense
组合运用,Suspense
现在还是处于试验阶段的特性。咱们打算在将来的某个发布版别中开发完结并提供文档 – 假如你现在感兴趣,能够参照tests看它是如何作业的。
界说组件其他装备
装备项的缺失,有时候咱们需求更改组件选项,在setup
中咱们现在是无法做到的。咱们需求在上方
再引进一个script
,在上方写入对应的export
即可,需求单开一个 script。
<script setup>
能够和一般的<script>
一同运用。一般的<script>
在有这些需求的状况下或许会被运用到:
- 无法在
<script setup>
声明的选项,例如inheritAttrs
或经过插件启用的自界说的选项。 - 声明命名导出。
- 运行副作用或许创立只需求履行一次的目标。
在script setup 外运用export default,其内容会被处理后放入原组件声明字段。
<script>
// 一般 `<script>`, 在模块范围下履行(只履行一次)
runSideEffectOnce()
// 声明额外的选项
export default {
name: "MyComponent",
inheritAttrs:false,
customOptions:{}
}
</script>
<scriptsetup>
import HelloWorld from '../components/HelloWorld.vue'
// 在 setup() 作用域中履行 (对每个实例皆如此)
//yourcode
</script>
<template>
<div>
<HelloWorld msg="Vue3 + TypeScript + Vite"/>
</div>
</template>
留意:Vue 3 SFC 一般会主动从组件的文件名推断出组件的 name。在大多数状况下,不需求明确的 name 声明。仅有需求的状况是当你需求
<keep-alive>
包括或排除或直接查看组件的选项时,你需求这个姓名。
参阅
Gaby
Vue
[木亦Sam](上手后才知道 ,Vue3 的 script setup 语法糖是真的爽 – ())