這就是一個語法
<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:檢視編譯的結果)
安裝 vite-plugin-inspect 外掛 https://www.npmjs.com/package/vite-plugin-inspect
setup 函式
template 模版
經過編譯,成了render 函式
setup 函式
經過編譯,什麼也沒有改變
script setup
template 模版
經過編譯,成了render 函式
script setup
的形式,編譯成了 setup函式,去執行,最終透過 expose 匯出
,所以<script setup>
就是一個語法糖,本質還是 setup 函式,只不過裡面自動做了一個expose
expose 是什麼(摘自vue 官方文件)
用於宣告當元件例項被父元件透過模板引用訪問時暴露的公共屬性。
預設情況下 setup 函式,會將元件例項向父元件暴露所有的例項屬性,這可能不是我們希望看到的
,而expose 就是限定子元件只能向外暴露哪些屬性/方法
元件具體例項觀察
<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 函式
,會將元件的屬性/例項, 相關隱藏屬性,全部暴露出去
透過 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>
script setup 如何暴露 方法/屬性
vue提供來一個全域性的宏來做屬性/方法的暴露。在編譯後,也是使用 expose 做屬性/方法暴露
<script setup> const msg = ref('setupScript') const count = ref(0) const increase = () => { count.value++ } defineExpose({ msg, count, increase }) </script>
但是如果不使用defineExpose做暴露 ,就不會暴露出任何屬性方法, 就像使用 setup 不用return ,就不會暴露出任何屬性方法,就像西方不能沒有耶路撒冷 !!!
全域性的宏 defineExpose 為什麼不需要匯入,就能直接使用?
透過外掛,可以看到,script setup 經過編譯 會變成setup 函式
,而 defineExpose 經過編譯
會變成expose
。所以 defineExpose 並不參與執行, 只參與編譯
。做一個對應關係
,所以不需要引入
編譯時? 執行時 傻傻分不清 ?
我們寫的template, script setup 不會直接執行
,而是經過一層編譯
。將template 模版編譯成render 函式,將 script setup 編譯成 setup 函式,將 defineExpose
編譯成 expose
,或者其他的宏函式defineModel
編譯成 props
,defineEmits
編譯成 emits
等等
這些宏函式
,只在編譯時起作用,和相關函式做一個對應關係
。並不會在執行時執行這些宏函式
,所以不需要引入這些宏函式
至此,我們已經明白了script setup 到底幹了什麼
總結
script setup 就是一個語法糖,經過 編譯,最終還是 setup 函式。
在 script setup 如果想獲取子元件的屬性/方法,需要透過 defineExpose 暴露
defineExpose 最終也會編譯成 expose, defineExpose不會參與執行時,所以不用做匯入。