一、使用與不使用 script setup 的對比
1、不使用 script setup 的繁雜性
我們之前的組件可能是這樣的:
<template>
<div>
<Card>{{msg}}</Card>
</div>
</template>
<script lang="ts"> import { ref, defineComponent } from "vue"; import Card from "./components/Card.vue"; export default defineComponent({ components: { Card, }, setup() { const msg = ref("setup script"); return { msg }; } }); </script>
這里做了兩件事,一個是導入並注冊組件,一個是導出一個字符串給template
使用。
如果模板上要使用的這些變量,必須要在 setup 返回的對象中定義。暴露變量必須 return 出來,如果我們內容很多的話,那么這個 setup 就會返回很多值,動輒十幾二十行,也是挺繁瑣的。有沒有更簡單的辦法,於是 script setup 語法出現。使用這個語法只需要在 script 標簽上加上 setup 屬性。
2、script setup 使用:啟用setup script
之后是這樣的
vue3.2 將這個之前的實驗功能變為正式功能,在單文件組件中引入了一種新的腳本類型:< script setup >。
<script lang="ts" setup> import { ref } from "vue"; import Card from "./components/Card.vue"; const msg = ref("setup script"); </script>
這里省去了組件的注冊步驟,也沒有顯式的導出變量的動作。你只需要在script
上配置setup
即可。
<script setup> import { ref } from 'vue'
// 像在平常的setup中code,但是不需要返回任何變量
const count = ref(0)//在此處定義的count可以直接在模板html中引用
const inc = () => {//函數也可以直接引用,而不用返回
count.value++ } </script>
<template>
<Foo :count="count" @click="inc" />
</template>
當 <script>
標簽具有 setup 屬性時,組件在編譯的過程中代碼運行的上下是 setup() 函數中。所有ES模塊導出都被認為是暴露給上下文的值,並包含在 setup() 返回對象中。
其實 script setup 就相當於在編譯運行是把代碼放到了 setup 函數中運行,然后把導出的變量定義到上下文中,並包含在返回的對象中。
二、如何使用 script setup 語法
1、導出變量和方法:在setup script
里面定義的所有變量都會自動導出,非常方便。
2、使用組件:所有的組件導入即可自動注冊。
需要注意一點的是:如何定義組件名 => name?
在 script setup 中,引入的組件可以直接使用,無需再通過components
進行注冊,並且無法指定當前組件的名字,它會自動以文件名為主。
如果需要定義類似 name 的屬性,可以再加個平級的 script 標簽,在里面實現即可。
3、使用 props - defineProps:使用 props
需要用到defineProps
來定義,具體用法跟之前的 props
寫法類似。
通過 defineProps
指定當前 props 類型的同時,獲得上下文的props對象。
在 script中 需要 props[key] 引用,而 template 中可直接調用 key。
<script lang="ts" setup> import { defineProps } from "vue"; const props = defineProps(['title', 'content']); </script>
// 給props定義類型:
const props = defineProps({ title: String, content: { type: Stirng, required: true } }); // 使用TS的注解的方式:
defineProps<{ title?: string content: string }>();
4、使用 emits - defineEmit:使用defineEmit
定義當前組件含有的事件,並通過返回的上下文去執行 emit
使用 defineEmit
對組件里面使用到的事件進行驗證和定義,具體用法跟之前一樣。
const emit = defineEmit(['onHeaderClick']) emit('onHeaderClick', 'params') // 還可以對事件進行驗證
const emit = defineEmit({ onHeaderClick: ({title}) => { if(!title) { console.warn('Invalid title') return false } return true } })
5、使用 context - useContext:使用 useContext
獲取上下文。
可以通過useContext
從上下文中獲取 slots 和 attrs。不過提案在正式通過后,廢除了這個語法,被拆分成了useAttrs
和useSlots
import { useContext } from 'vue'
const { slots, attrs } = useContext() // 獲取到的slots attrs跟之前的setup里面的是一樣的。
6、使用Slots和Attrs:需要useSlots, useAttrs
<script setup> import { useSlots, useAttrs } from 'vue'
const slots = useSlots() const attrs = useAttrs() </script>
7、指令:指令跟組件一樣,導入自定注冊。
<script setup> import {color as superColor} from './v-color'
</script>
<template>
<div v-super-color />
</template>
// 導入的 color 重命名為 superColor,並自動映射為指令v-super-color
8、defineExpose API
傳統的寫法,我們可以在父組件中,通過 ref 實例的方式去訪問子組件的內容,但在 script setup 中,該方法就不能用了,setup 相當於是一個閉包,除了內部的 template
模板,誰都不能訪問內部的數據和方法。
如果需要對外暴露 setup 中的數據和方法,需要使用 defineExpose API。示例:
<script setup> import { defineExpose } from 'vue'
const a = 1
const b = 2 defineExpose({ a }) // 將 a 暴露出去
</script>
三、setup 目前存在的限制
1、配置項的缺失:修改選項配置需要單開一個 script
有時候我們需要更改組件選項,在 setup 中我們目前是無法做到的。我們需要在上方
再引入一個 script
,在上方寫入對應的 export
即可。
<script> export default { name: 'YourName', inheritAttrs: false, customOptions: {}, } </script>
<script setup>
// your code
</script>
注意:Vue 3 SFC 一般會自動從組件的文件名推斷出組件的 name。在大多數情況下,不需要明確的 name 聲明。唯一需要的情況是當你需要 <keep-alive>
包含或排除或直接檢查組件的選項時,你需要這個名字。