Vue3.2單文件組件setup的語法總結(jié)

setup語法糖

    setup是Vue3.0后推出的語法糖,并且在Vue3.2版本進(jìn)行了大更新,像寫普通JS一樣寫vue組件,對于開發(fā)者更加友好了;按需引入computed、watch、directive等選項,一個業(yè)務(wù)邏輯可以集中編寫在一起,讓代碼更加簡潔便于瀏覽。

1. 基本用法

只需在<script>里添加一個setup屬性,編譯時會把<script setup></script>里的代碼編譯成一個setup函數(shù)

<script setup>
console.log('hello script setup')
</script>

普通的<script>只會在組件被首次引入的時候執(zhí)行一次,<script setup>里的代碼會在每次組件實例被創(chuàng)建的時候執(zhí)行。

2. data和methods

<script setup>里聲明的變量和函數(shù),不需要return暴露出去,就可以直接在template使用

<script setup>
import { ref, reactive } from 'vue'    
// 普通變量
const msg = 'Hello!'
 
// 響應(yīng)式變量
let num = ref(1111)         // ref聲明基本類型變量
const obj = reactive({        // reactive聲明對象類型變量,如Object、Array、Date...
    key: 'this is a object'
})
 
// 函數(shù)
function log() {
    console.log(msg)          // Hello
    console.log(num.value)    // 1111(可根據(jù)input輸入值而改變)
    console.log(obj.key)      // this is a object
}
</script>
 
<template>
    <h1>{{ msg }}</h1>
    <p>{{obj.key}}</p>
    <input v-model="num" type="text" />
    <button @click="log">打印日志</button>
</template>

3.計算屬性computed

<script setup>
import { ref, computed } from 'vue'
 
let count = ref(0)
const countPlus = computed(()=>{
    return count.value+1
})
</script>
 
<template>
    <h1>計數(shù):{{ countPlus }}</h1>
</template>

4. 監(jiān)聽器watch、watchEffect

1、watch監(jiān)聽器除了使用方式有區(qū)別之外,其他的與vue2.0沒啥變化

<script setup>
import { ref, reactive, watch } from 'vue'
 
// 監(jiān)聽ref
let count = ref(0)
watch(count, (newVal, oldVal)=> {
    console.log('修改后', newVal)
    console.log('修改前', oldVal)
})
 
// 監(jiān)聽reactive屬性
const obj = reactive({
    count: 0
})
watch(
    ()=> obj.count,     // 一個函數(shù),返回監(jiān)聽屬性
    (newVal, oldVal)=> {
        console.log('修改后', newVal)
        console.log('修改前', oldVal)
    },
    {
        immediate: true,     // 立即執(zhí)行,默認(rèn)為false
        deep: true     // 深度監(jiān)聽,默認(rèn)為false
    }
)
 
const onChange = function(){
    count.value++
    obj.count++
}
</script>
 
<template>
    <button @click="onChange">改變count</button>
</template>

2、watchEffect

watchEffect是Vue3.0新增的一個監(jiān)聽屬性的方法,它與watch的區(qū)別在于watchEffect不需要指定監(jiān)聽對象,回調(diào)函數(shù)里可直接獲取到修改后的屬性的值

<script setup>
import { ref, reactive, watchEffect } from 'vue'
 
let count = ref(0)
const obj = reactive({
    count: 0
})
setTimeout(()=>{
    count.value++
    obj.count++
}, 1000)
 
watchEffect(()=> {
    console.log('修改后的count', count.value)
    console.log('修改前的obj', obj.value)
})
</script>

5.自定義指令directive

以 vNameOfDirective 的形式來命名本地自定義指令,可以直接在模板中使用

<script setup>
// 導(dǎo)入指令可重命名
// import { myDirective as vMyDirective } from './MyDirective.js'
 
// 自定義指令
const vMyDirective = {
  beforeMount: (el) => {
    // 在元素上做些操作
  }
}
</script>
<template>
  <h1 v-my-directive>This is a Heading</h1>
</template>

6. import導(dǎo)入的內(nèi)容可直接使用

1、導(dǎo)入的模塊內(nèi)容,不需要通過 methods 來暴露它

// utils.js 
export const onShow = function(name) {
    return 'my name is ' + name
}
// Show.vue
<script setup>
    import { onShow } from './utils.js'
</script>
<template>
    <div>{{ onShow('jack') }}</div>
</template>

2、導(dǎo)入外部組件,不需要通過components注冊使用

// Child.vue
<template>
    <div>I am a child</div>
</template>
// Parent.vue
<script setup>
    import Child from './Child.vue'
</script>
<template>
    <child></child>
</template>

7. 聲明props和emits

使用 defineProps 和 defineEmits API 來聲明 props 和 emits

// Child.vue
<script setup>
import { defineProps, defineEmits } from 'vue'
 
// 聲明props
const props = defineProps({
    info: {
        type: String,
        default: ''
    }
})
 
// 聲明emits
const $emit = defineEmits(['change'])
 
const onChange = function() {
    $emit('change', 'child返回值')
}
</script>
 
<template>
    <h1>信息:{{ info }}</h1>
    <button @click="onChange">點擊我</button>
</template>
// Parent.vue
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
 
const msg = ref('hello setup !')    // 響應(yīng)式變量
 
const onAction = function(event) {
    console.log(event)    // child返回值
}
</script>
 
<template>
    <child :info="msg" @change="onAction"></child>
</template>

8. 父組件獲取子組件的數(shù)據(jù)

父組件要想通過ref獲取子組件的變量或函數(shù),子組件須使用defineExpose暴露出去

// Child.vue
<script setup>
import { ref, defineExpose } from 'vue'
 
const info = ref('I am child')
const onChange = function() {
    console.log('Function of child')
}
 
// 暴露屬性
defineExpose({
    info,
    onChange
})
</script>
 
<template>
    <h1>信息:{{ info }}</h1>
    <button @click="onChange">點擊我</button>
</template>
// Parent.vue
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
 
const childRef = ref()
const onAction = function() {
    console.log(childRef.value.info)    // I am child
    console.log(childRef.value.onChange())    // Function of child
}
</script>
 
<template>
    <child ref="childRef"></child>
    <button @click="onAction">獲取子值</button>
</template>

9. provide和inject傳值

無論組件層次結(jié)構(gòu)有多深,父組件都可以通過provide 選項來其所有子組件提供數(shù)據(jù),子組件通過inject接收數(shù)據(jù)

// Parent.vue
<script setup>
import { ref, provide } from 'vue'
import Child from './Child.vue'
 
const msg = ref('Hello, my son')
const onShow = function() {
    console.log('I am your parent')
}
 
provide('myProvide', {
    msg,
    onShow
})
</script>
 
<template>
    <child></child>
</template>
// Child.vue
<script setup>
import { inject } from 'vue'
 
const provideState = inject('myProvide')    // 接收參數(shù)
 
const getData = function() {
    console.log(provideState.msg)    // Hello, my son
    console.log(provideState.onShow())    // I am your parent
}
</script>
 
<template>
    <button @click="getData">獲取父值</button>
</template>

10. 路由useRoute和useRouter

<script setup>
import { useRoute, useRouter } from 'vue'
 
const $route = useRoute()
const $router = userRouter()
 
// 路由信息
console.log($route.query)
 
// 路由跳轉(zhuǎn)
$router.push('/login')
</script>

11. 對await異步的支持

<script setup> 中可以使用頂層 await。結(jié)果代碼會被編譯成 async setup()

<script setup>
    const post = await fetch(`/api/post/1`).then(r => r.json())
</script>

12. nextTick

// 方式一
<script setup>
import { nextTick } from 'vue'
 
nextTick(()=>{
    console.log('Dom已更新!')
})
</script>
// 方式二
<script setup>
import { nextTick } from 'vue'
 
await nextTick()    // nextTick是一個異步函數(shù),返回一個Promise實例
// console.log('Dom已更新!')
</script>

13. 全局屬性globalProperties

// main.js里定義
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
 
// 定義一個全局屬性$global 
app.config.globalProperties.$global = 'This is a global property.' 
 
app.mount('#app')
// 組件內(nèi)使用
<script setup>
import { getCurrentInstance } from 'vue'
 
// 獲取vue實例
const { proxy } = getCurrentInstance()
// 輸出
console.log(proxy.$global)    // This is a global property.
</script>

14. 生命周期

setup()里訪問組件的生命周期需要在生命周期鉤子前加上“on”,并且沒有beforeCreate和created生命周期鉤子

因為 setup 是圍繞 beforeCreate 和 created 生命周期鉤子運行的,所以不需要顯式地定義它們。換句話說,在這些鉤子中編寫的任何代碼都應(yīng)該直接在 setup 函數(shù)中編寫。


image.png
// 使用方式
<script setup>
import { onMounted } from 'vue'
 
onMounted(()=> {
    console.log('onMounted')
})
</script>

15. 與普通的script標(biāo)簽一起使用

<script setup> 可以和普通的 <script> 一起使用。普通的 <script> 在有這些需要的情況下或許會被使用到:

  1. 無法在 <script setup> 聲明的選項,例如 inheritAttrs 或通過插件啟用的自定義的選項;
  2. 聲明命名導(dǎo)出,<script setup>定義的組件默認(rèn)以組件文件的名稱作為組件名;
  3. 運行副作用或者創(chuàng)建只需要執(zhí)行一次的對象。
<script>
// 普通 <script>, 在模塊范圍下執(zhí)行(只執(zhí)行一次)
runSideEffectOnce()
 
// 聲明額外的選項
export default {
  name: 'ComponentName',    // 組件重命名
  inheritAttrs: false,
  customOptions: {}
}
</script>
 
<script setup>
// 在 setup() 作用域中執(zhí)行 (對每個實例皆如此)
</script>

16. v-memo新指令該指令與v-once類似,v-once是只渲染一次之后的更新不再渲染,而v-memo是根據(jù)條件來渲染。該指令接收一個固定長度的數(shù)組作為依賴值進(jìn)行記憶比對,如果數(shù)組中的每個值都和上次渲染的時候相同,則該元素(含子元素)不刷新。

1、應(yīng)用于普通元素或組件;

<template>
<-- 普通元素 -->
<div v-memo="[valueA, valueB]">
  ... 
</div>
 
<-- 組件 -->
<component v-memo="[valueA, valueB]"></component>
</template>
 
<script setup>
import component from "../compoents/component.vue"
</script>

當(dāng)組件重新渲染的時候,如果 valueA 與 valueB 都維持不變,那么對這個 <div> 以及它的所有子節(jié)點的更新都將被跳過。
2、結(jié)合v-for使用
v-memo 僅供性能敏感場景的針對性優(yōu)化,會用到的場景應(yīng)該很少。渲染 v-for 長列表 (長度大于 1000) 可能是它最有用的場景:

<template>
<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
  <p>ID: {{ item.id }} - selected: {{ item.id === selected }}</p>
  <p>...more child nodes</p>
</div>
</template>

作者:用戶體驗官大龍
鏈接:https://juejin.cn/post/7095392368064462879
來源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容