切換語言為:簡體
Vue3 中 <script setup> 到底幹了什麼

Vue3 中 <script setup> 到底幹了什麼

  • 爱糖宝
  • 2024-07-02
  • 2081
  • 0
  • 0

這就是一個語法

<script setup> 這是vue的一個語法,大家都這樣用。寫在裡面的變數/函式,都相當於包在setup函式中一樣。下面是一個簡單的對比

  • setup函式

<script>
export default {
	setup() {
		const count = ref(0)
		const msg = ref('setupScript')
		const increase = () => {
			count.value++
			console.log(count.value)
		}
		return {
			count,
			msg,
			increase
		}
	}
}
</script>


  • setup 語法糖(當然如果需要子元件的屬性/變數,這裏需要defineExpose 做匯出)

<script setup>
const count = ref(0)
const msg = ref('setupScript')
const increase = () => {
	count.value++
}
</script>


透過Inspect 來觀察 script setup和  setup 函式的區別(vite-plugin-inspect:檢視編譯的結果)

Vue3 中 <script setup> 到底幹了什麼

setup 函式

  • template 模版 經過編譯,成了render 函式

  • setup 函式 經過編譯,什麼也沒有改變

Vue3 中 <script setup> 到底幹了什麼

script setup

  • template 模版 經過編譯,成了render 函式

  • script setup 的形式,編譯成了 setup函式,去執行,最終透過 expose 匯出,所以 <script setup> 就是一個語法糖,本質還是 setup 函式,只不過裡面自動做了一個expose

Vue3 中 <script setup> 到底幹了什麼

expose 是什麼(摘自vue 官方文件)

用於宣告當元件例項被父元件透過模板引用訪問時暴露的公共屬性。

預設情況下 setup 函式,會將元件例項向父元件暴露所有的例項屬性,這可能不是我們希望看到的,而expose 就是限定子元件只能向外暴露哪些屬性/方法

Vue3 中 <script setup> 到底幹了什麼

元件具體例項觀察

<template>
	<SetupFun ref="setupFunRef" />
	<SetupScript ref="setupScriptRef" />
</template>
<script setup>
import SetupFun from './components/setupFun.vue'
import SetupScript from './components/setupScript.vue'

const setupFunRef = ref(null)
const setupScriptRef = ref(null)

onMounted(() => {
	console.log('%c [ setup 函式 ]-15', 'font-size:16px; background:pink; color:#bf2c9f;', setupFunRef.value)

	console.log('%c [setup 語法糖  ]-23', 'font-size:16px; background:pink; color:#bf2c9f;', setupScriptRef.value)
	console.log('%c [setup 語法糖  ]-23', 'font-size:16px; background:pink; color:#bf2c9f;', setupScriptRef.value.$el)
})
</script>


透過 setup 函式,會將元件的屬性/例項, 相關隱藏屬性,全部暴露出去

Vue3 中 <script setup> 到底幹了什麼

透過 script setup什麼都沒有暴露出去

Vue3 中 <script setup> 到底幹了什麼

setup 函式不香嗎,為什麼還要 script setup ?

setup 函式,會將 元件例項屬性/API 全部暴露給父元件。好是好,使用起來變得超級方便,但是這也存在一個潛在的巨大問題,父子元件完全沒有邊界,$root,$parent,$el 隨便用,元件很可能擁有一些應保持私有的內部狀態或方法,以避免緊耦合, 也會導致單項數據流被打破,時間久了,容易造成資料混亂,變成一堆石山。這裏爲了方便沒有舉例項屬性,舉了一個方法來說明如何破壞單項數據流

比如:

onMounted(() => {
         // 在父元件呼叫子元件的increase,
        //而子元件的increase 裡寫了修改 count的邏輯
        console.log('%c [ setup 函式 ]-15',  setupFunRef.value.increase()) 
        
	console.log('%c [ setup 函式 ]-16',  setupFunRef.value.count) // count由 0 -》1 在
 }


可以指定特定暴露屬性/方法嗎?->expose

   <script>
export default {
	setup(props, { expose }) {
		const count = ref(0)
		const msg = ref('setupScript')
		const increase = () => {
			count.value++
			console.log(count.value)
		}
                // 透過 expost 指定暴露當法,同時不會向外暴露子元件例項上的所有例項屬性
		expose({
			count,
			msg,
			increase
		})
	}
}
</script>


Vue3 中 <script setup> 到底幹了什麼

Vue3 中 <script setup> 到底幹了什麼

script setup 如何暴露 方法/屬性

vue提供來一個全域性的宏來做屬性/方法的暴露。在編譯後,也是使用 expose 做屬性/方法暴露

<script setup>
const msg = ref('setupScript')
const count = ref(0)
const increase = () => {
	count.value++
}
defineExpose({ msg, count, increase })
</script>


Vue3 中 <script setup> 到底幹了什麼

Vue3 中 <script setup> 到底幹了什麼

但是如果不使用defineExpose做暴露 ,就不會暴露出任何屬性方法, 就像使用 setup 不用return ,就不會暴露出任何屬性方法,就像西方不能沒有耶路撒冷 !!!

全域性的宏 defineExpose 為什麼不需要匯入,就能直接使用?

透過外掛,可以看到,script setup 經過編譯 會變成setup 函式,而 defineExpose 經過編譯 會變成expose。所以   defineExpose 並不參與執行, 只參與編譯做一個對應關係,所以不需要引入

編譯時? 執行時 傻傻分不清 ?

我們寫的template, script setup 不會直接執行,而是經過一層編譯。將template 模版編譯成render 函式,將 script setup 編譯成 setup 函式,將 defineExpose 編譯成 expose,或者其他的宏函式defineModel編譯成 propsdefineEmits編譯成 emits 等等

這些宏函式只在編譯時起作用,和相關函式做一個對應關係並不會在執行時執行這些宏函式,所以不需要引入這些宏函式

至此,我們已經明白了script setup 到底幹了什麼

總結

  • script setup 就是一個語法糖,經過 編譯,最終還是 setup 函式。

  • 在 script setup 如果想獲取子元件的屬性/方法,需要透過 defineExpose 暴露

  • defineExpose 最終也會編譯成 expose, defineExpose不會參與執行時,所以不用做匯入。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.