Vue3編程流暢技巧使用setup語法糖拒絕寫return
Vue3.2 setup語法糖
Vue3.2 setup語法糖 [ 單文件組件的語法糖<script setup>
]
如果你對Vue3語法糖有一定瞭解,配和我另外一篇一起食用更好哦!Vue3必學技巧-自定義Hooks-讓寫Vue3更暢快
閱讀本來,默認你已經對Vue3.0的composition API有一定瞭解,但困擾於setup函數內需要繁瑣return相關的變量和函數,那setup的語法糖<script setup>
你將收獲滿滿。語法糖<script setup>
的引入讓你寫Vue3更爽,讓Vue3更豐滿。本文是在官方文檔基礎上寫的,如果有時間,建議上官方文檔上看,本文寫得更為語義化和通俗,希望你能喜歡。
<script setup>
是在單文件組件 (SFC) 中使用組合式 API 的編譯時語法糖
解決Vue3.0中setup需要繁瑣將聲明的變量、函數以及 import 引入的內容通過return向外暴露,才能在<template/>
使用的問題
1.<script setup>在<template/>使用
<script setup>
中無需return 聲明的變量、函數以及import引入的內容,即可在<template/>
使用
<script setup>
語法糖
<script setup> //import引入的內容 import { getToday } from './utils' // 變量 const msg = 'Hello!' // 函數 function log() { console.log(msg) } </script> //在template中直接使用聲明的變量、函數以及import引入的內容 <template> <div @click="log">{{ msg }}</div> <p>{{getToday()}}</p> </template>
標準組件<script>
需要寫setup函數並繁瑣retrun
<script> //import引入的內容 import { getToday } from './utils' export default{ setup(){ // 變量 const msg = 'Hello!' // 函數 function log() { console.log(msg) } //想在tempate裡面使用需要在setup內return暴露出來 return{ msg, log, getToday } } } </script> <template> <div @click="log">{{ msg }}</div> <p>{{getToday()}}</p> </template>
小結:<script setup>
語法糖裡面的代碼會被編譯成組件 setup()
函數的內容,不需要通過return暴露 聲明的變量、函數以及import引入的內容,即可在<template/>
使用,並且不需要寫export default{}
<script setup>
語法糖裡面的代碼會被編譯成組件 setup()
函數的內容。這意味著與普通的 <script>
隻在組件被首次引入的時候執行一次不同,<script setup>
中的代碼會在每次組件實例被創建的時候執行
<script> console.log('script');//多次實例組件,隻觸發一次 export default { setup() { console.log('setupFn');//每次實例化組件都觸發和script-setup標簽一樣 } } </script>
(script-setup標簽最終都會編譯成setup()
函數的內容,每次實例化組件,就是實例化一次setup函數。script標簽裡面的setup函數也是一樣每次實例化組件,就是實例化一次setup函數,但是script標簽setup是需要寫在export default{}內的,外的隻是首次引入的時候執行一次)
2、<script setup>引入組件將自動註冊
不需要在引入組件後,通過 components:{}
註冊組件,可直接使用
<script setup> import MyComponent from './MyComponent.vue' //components:{MyComponent} 不需要註冊直接使用 </script> <template> <MyComponent /> </template>
3、組件通信:
在<script setup>
中必須使用 defineProps
和 defineEmits
API 來替代 props 和 emits
defineProps
和 defineEmits
具備完整的類型推斷並且在 <script setup>
中是直接可用的(瀏覽瞭一下掘金,發現大部分文章demo還是通過import引入這2個api,這點官方文檔寫得很清楚)
defineProps 代替props
接收父組件傳遞的數據(父組件向子組件傳參)
父組件:
<template> <div>父組件</div> <Child :title="msg" /> </template> <script setup> import {ref} from 'vue' import Child from './child.vue' const msg = ref('父的值') //自動返回,在template直接解套使用 </script>
子組件:
<template/>
中可以直接使用父組件傳遞的props (可省略props.)
<script-setup>
需要通過props.xx獲取父組件傳遞過來的props
<template> <div>子組件</div> <div>父組件傳遞的值:{{title}}</div> </template> <script setup> //import {defineProps} from 'vue' 不需要引入 //語法糖必須使用defineProps替代props const props = defineProps({ title: { type: String } }); //script-setup 需要通過props.xx獲取父組件傳遞過來的props console.log(props.title) //父的值 </script>
defineEmit 代替emit
子組件向父組件傳遞數據(子組件向外暴露數據)
子組件代碼:
<template> <div>子組件</div> <button @click="toEmits">子組件向外暴露數據</button> </template> <script setup> import {ref} from 'vue' const name = ref('我是子組件') //1、暴露內部數據 const emits = defineEmits(['childFn']); const toEmits = () => { //2、觸發父組件中暴露的childFn方法並攜帶數據 emits('childFn',name) } </script>
父組件代碼:
<template> <div>父組件</div> <Child @childFn='childFn' /> <p>接收子組件傳遞的數據{{childData}} </p> </template> <script setup> import {ref} from 'vue' import Child from './child.vue' const childData = ref(null) const childFn=(e)=>{ consloe.log('子組件觸發瞭父組件childFn,並傳遞瞭參數e') childData=e.value } </script>
4.<script setup>需主動向父組件暴露子組件屬性 :defineExpose
使用 <script setup>
的組件,父組件是無法通過ref 或者 $parent
獲取到子組件的ref等響應數據,需要通過defineExpose 主動暴露
子組件代碼:
<script setup> import { ref } from 'vue' const a = 1 const b = ref(2) //主動暴露組件屬性 defineExpose({ a, b }) </script>
父組件代碼:
<template> <div>父組件</div> <Child ref='childRef' /> <button @click='getChildData'>通過ref獲取子組件的屬性 </button> </template> <script setup> import {ref} from 'vue' import Child from './child.vue' const childRef= ref() //註冊響應數據 const getChildData =()=>{ //子組件接收暴露出來得值 console.log(childRef.value.a) //1 console.log(childRef.value.b) //2 響應式數據 } </script>
5.語法糖其他功能
useSlots
和 useAttrs
(少用,由於大部分人是SFC模式開發,在<template/>
通過<slot/>
標簽就可以渲染插槽)
如果需要在script-setup
中使用 slots
和 attrs
需要用useSlots
和 useAttrs
替代
需要引入:import { useSlots ,useAttrs } form 'vue'
在<template/>
中通過 $slots
和 $attrs
來訪問更方便(attrs用來獲取父組件中非props的傳遞到子組件的參數/方法,attrs 用來獲取父組件中非props的傳遞到子組件的參數/方法,attrs用來獲取父組件中非props的傳遞到子組件的參數/方法,slots可以獲取父組件中插槽傳遞的虛擬dom對象,在SFC模式應該用處不大,在JSX /TSX使用比較多)
父組件:
<template> <Child msg="非porps傳值子組件用attrs接收" > <!-- 匿名插槽 --> <span >默認插槽</span> <!-- 具名插槽 --> <template #title> <h1>具名插槽</h1> </template> <!-- 作用域插槽 --> <template #footer="{ scope }"> <footer>作用域插槽——姓名:{{ scope.name }},年齡{{ scope.age }}</footer> </template> </Child> </template> <script setup> // 引入子組件 import Child from './child.vue' </script>
子組件:
<template> <!-- 匿名插槽 --> <slot /> <!-- 具名插槽 --> <slot name="title" /> <!-- 作用域插槽 --> <slot name="footer" :scope="state" /> <!-- $attrs 用來獲取父組件中非props的傳遞到子組件的參數 --> <p>{{ attrs.msg == $attrs.msg }}</p> <!--true 沒想到有啥作用... --> <p>{{ slots == $slots }}</p> </template> <script setup> import { useSlots, useAttrs, reactive, toRef } from 'vue' const state = reactive({ name: '張三', age: '18' }) const slots = useSlots() console.log(slots.default()); //獲取到默認插槽的虛擬dom對象 console.log(slots.title()); //獲取到具名title插槽的虛擬dom對象 // console.log(slots.footer()); //報錯 不知道為啥有插槽作用域的無法獲取 //useAttrs() 用來獲取父組件傳遞的過來的屬性數據的(也就是非 props 的屬性值)。 const attrs = useAttrs() </script>
useSlots或許在JSX/TSX下更實用
想使用JSX語法在vite需要下載相關jsx的plugins才能識別jsx
useSlots 可以獲取父組件傳遞過來插槽的虛擬dom對象,可以用來渲染插槽內容
<script lang='jsx'> import { defineComponent, useSlots } from "vue"; export default defineComponent({ setup() { // 獲取插槽數據 const slots = useSlots(); // 渲染組件 return () => ( <div> {slots.default?slots.default():''} {slots.title?slots.title():''} </div> ); }, }); </script>
大部分人是SFC模式開發,在<template/>
通過<slot/>
標簽就可以渲染插槽,這種JSX 的寫法應該是很少人會使用的
6.在setup訪問路由
- 訪問路由實例組件信息:route和router
setup
裡不能訪問 this
,不能再直接訪問 this.$router
或 this.$route
。(getCurrentInstance可以替代this但不推薦)
推薦:使用useRoute
函數和useRouter
函數替代this.$route
和 this.$router
<script setup> import { useRouter, useRoute } from 'vue-router' const route = useRoute() const router = useRouter() function pushWithQuery(query) { router.push({ name: 'search', query: { ...route.query, }, }) } <script/>
- 導航守衛
仍然可以使用路由實例組件的導航守衛
import router from './router' router.beforeEach((to,from,next)=>{ })
也可以使用組合式api的導航守衛onBeforeRouteLeave, onBeforeRouteUpdate
<script setup> import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router' // 與 beforeRouteLeave 相同,無法訪問 `this` onBeforeRouteLeave((to, from) => { const answer = window.confirm( 'Do you really want to leave? you have unsaved changes!' ) // 取消導航並停留在同一頁面上 if (!answer) return false }) const userData = ref() // 與 beforeRouteUpdate 相同,無法訪問 `this` onBeforeRouteUpdate(async (to, from) => { //僅當 id 更改時才獲取用戶,例如僅 query 或 hash 值已更改 if (to.params.id !== from.params.id) { userData.value = await fetchUser(to.params.id) } }) <script/>
組合式 API 守衛也可以用在任何由 `<router-view>` 渲染的組件中,它們不必像組件內守衛那樣直接用在路由組件上。
小結:setup的語法糖作為Vue3的補充,讓Vue3更加豐滿,讓我們寫Vue3更爽。如果覺得寫得還不錯不吝嗇給點給贊再走吧!
如果你看完後覺得意猶未盡,似乎沒get到Vue3究竟好在哪?請瞭解下Vue3的自定義Hooks!
Vue3配合自定義Hooks或許才是Vue3的完全體!因為有部分人看完這篇後,還覺得Vue3函數和變量寫在一起不優雅!不妨看下這篇!
Vue3編程流暢技巧自定義Hooks
以上就是Vue3編程流暢技巧使用setup語法糖拒絕寫return的詳細內容,更多關於Vue3編程setup語法糖的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- vue3中單文件組件<script setup>實例詳解
- Slots Emit和Props穿透組件封裝實現摸魚加鐘
- Vue3的7種種組件通信詳情
- Vue3常用的通訊方式總結與實例代碼
- vue3組件通信的方式總結及實例用法