<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
滿滿的乾貨,建議收藏慢慢看,可以當作Vue3.0的學習資料。
在vue2.0時期,元件裡定義的各類變數、方法、計算屬性等是分別存放到data、methods、computed...選項裡,這樣編寫的程式碼不便於後期的查閱(查詢一個業務邏輯需要在各個選項來回切換)。setup函數的推出就是為了解決這個問題,讓新手開發者更容易上手...
setup是Vue3.0後推出的語法糖,並且在Vue3.2版本進行了大更新,像寫普通JS一樣寫vue元件,對於開發者更加友好了;按需引入computed、watch、directive等選項,一個業務邏輯可以集中編寫在一起,讓程式碼更加簡潔便於瀏覽。
只需在<script>裡新增一個setup屬性,編譯時會把<script setup></script>裡的程式碼編譯成一個setup函數
<script setup> console.log('hello script setup') </script>
普通的<script>只會在元件被首次引入的時候執行一次,<script setup>裡的程式碼會在每次元件範例被建立的時候執行。
<script setup>裡宣告的變數和函數,不需要return暴露出去,就可以直接在template使用
<script setup> import { ref, reactive } from 'vue' // 普通變數 const msg = 'Hello!' // 響應式變數 let num = ref(1111) // ref宣告基本型別變數 const obj = reactive({ // reactive宣告物件型別變數,如Object、Array、Date... key: 'this is a object' }) // 函數 function log() { console.log(msg) // Hello console.log(num.value) // 1111(可根據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>
<script setup> import { ref, computed } from 'vue' let count = ref(0) const countPlus = computed(()=>{ return count.value+1 }) </script> <template> <h1>計數:{{ countPlus }}</h1> </template>
1、watch監聽器除了使用方式有區別之外,其他的與vue2.0沒啥變化
<script setup> import { ref, reactive, watch } from 'vue' // 監聽ref let count = ref(0) watch(count, (newVal, oldVal)=> { console.log('修改後', newVal) console.log('修改前', oldVal) }) // 監聽reactive屬性 const obj = reactive({ count: 0 }) watch( ()=> obj.count, // 一個函數,返回監聽屬性 (newVal, oldVal)=> { console.log('修改後', newVal) console.log('修改前', oldVal) }, { immediate: true, // 立即執行,預設為false deep: true // 深度監聽,預設為false } ) const onChange = function(){ count.value++ obj.count++ } </script> <template> <button @click="onChange">改變count</button> </template>
2、watchEffect
watchEffect是Vue3.0新增的一個監聽屬性的方法,它與watch的區別在於watchEffect不需要指定監聽物件,回撥函數裡可直接獲取到修改後的屬性的值
<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>
以 vNameOfDirective
的形式來命名本地自定義指令,可以直接在模板中使用
<script setup> // 匯入指令可重新命名 // import { myDirective as vMyDirective } from './MyDirective.js' // 自定義指令 const vMyDirective = { beforeMount: (el) => { // 在元素上做些操作 } } </script> <template> <h1 v-my-directive>This is a Heading</h1> </template>
1、匯入的模組內容,不需要通過 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、匯入外部元件,不需要通過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>
在 <script setup>
中必須使用 defineProps
和 defineEmits
API 來宣告 props
和 emits
,它們具備完整的型別推斷並且在 <script setup>
中是直接可用的
// Child.vue <script setup> // 宣告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 !') // 響應式變數 const onAction = function(event) { console.log(event) // child返回值 } </script> <template> <child :info="msg" @change="onAction"></child> </template>
如果使用了 Typescript,使用純型別宣告來宣告 prop 和 emits 也是可以的。
父元件要想通過ref獲取子元件的變數或函數,子元件須使用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>
無論元件層次結構有多深,父元件都可以通過provide
選項來其所有子元件提供資料,子元件通過inject接收資料
// 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') // 接收引數 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>
<script setup> import { useRoute, useRouter } from 'vue-router' const $route = useRoute() const $router = userRouter() // 路由資訊 console.log($route.query) // 路由跳轉 $router.push('/login') </script>
<script setup>
中可以使用頂層 await
。結果程式碼會被編譯成 async setup()
<script setup> const post = await fetch(`/api/post/1`).then(r => r.json()) </script>
十二、nextTick
// 方式一 <script setup> import { nextTick } from 'vue' nextTick(()=>{ console.log('Dom已更新!') }) </script>
// 方式二 <script setup> import { nextTick } from 'vue' await nextTick() // nextTick是一個非同步函數,返回一個Promise範例 // console.log('Dom已更新!') </script>
// 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')
// 元件內使用 <script setup> import { getCurrentInstance } from 'vue' // 獲取vue範例 const { proxy } = getCurrentInstance() // 輸出 console.log(proxy.$global) // This is a global property. </script>
setup()裡存取元件的生命週期需要在生命週期勾點前加上“on”,並且沒有beforeCreate和created生命週期勾點
因為
setup
是圍繞beforeCreate
和created
生命週期勾點執行的,所以不需要顯式地定義它們。換句話說,在這些勾點中編寫的任何程式碼都應該直接在setup
函數中編寫。
// 使用方式 <script setup> import { onMounted } from 'vue' onMounted(()=> { console.log('onMounted') }) </script>
<script setup>
可以和普通的 <script>
一起使用。普通的 <script>
在有這些需要的情況下或許會被使用到:
<script setup>
宣告的選項,例如 inheritAttrs
或通過外掛啟用的自定義的選項;<script setup>
定義的元件預設以元件檔案的名稱作為元件名;<script> // 普通 <script>, 在模組範圍下執行(只執行一次) runSideEffectOnce() // 宣告額外的選項 export default { name: 'ComponentName', // 元件重新命名 inheritAttrs: false, customOptions: {} } </script> <script setup> // 在 setup() 作用域中執行 (對每個範例皆如此) </script>
該指令與v-once類似,v-once是隻渲染一次之後的更新不再渲染,而v-memo是根據條件來渲染。該指令接收一個固定長度的陣列作為依賴值進行記憶比對,如果陣列中的每個值都和上次渲染的時候相同,則該元素(含子元素)不重新整理。
1、應用於普通元素或元件;
<template> <-- 普通元素 --> <div v-memo="[valueA, valueB]"> ... </div> <-- 元件 --> <component v-memo="[valueA, valueB]"></component> </template> <script setup> import component from "../compoents/component.vue" </script>
當元件重新渲染的時候,如果 valueA
與 valueB
都維持不變,那麼對這個 <div>
以及它的所有子節點的更新都將被跳過。
2、結合v-for
使用
v-memo
僅供效能敏感場景的針對性優化,會用到的場景應該很少。渲染 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>
當selected發生變化時,只有item.id===selected的該項重新渲染,其餘不重新整理。
Vue3.2版本對單檔案元件的style樣式進行了很多升級,如區域性樣式、css變數以及樣式暴露給模板使用等。
當 <style>
標籤帶有 scoped
attribute 的時候,它的 CSS 只會應用到當前元件的元素上:
<template> <div class="example">hi</div> </template> <style scoped> .example { color: red; } </style>
處於 scoped
樣式中的選擇器如果想要做更“深度”的選擇,也即:影響到子元件,可以使用 :deep()
這個偽類:
<style scoped> .a :deep(.b) { /* ... */ } </style>
通過
v-html
建立的 DOM 內容不會被作用域樣式影響,但你仍然可以使用深度選擇器來設定其樣式。
預設情況下,作用域樣式不會影響到 <slot/>
渲染出來的內容,因為它們被認為是父元件所持有並傳遞進來的。使用 :slotted
偽類以確切地將插槽內容作為選擇器的目標:
<style scoped> :slotted(div) { color: red; } </style>
如果想讓其中一個樣式規則應用到全域性,比起另外建立一個 <style>
,可以使用 :global
偽類來實現:
<style scoped> :global(.red) { color: red; } </style>
你也可以在同一個元件中同時包含作用域樣式和非作用域樣式:
<style> /* global styles */ </style> <style scoped> /* local styles */ </style>
<style module>
標籤會被編譯為 CSS Modules 並且將生成的 CSS 類鍵暴露給元件:
1、 預設以$style
物件暴露給元件;
<template> <p :class="$style.red"> This should be red </p> </template> <style module> .red { color: red; } </style>
2、可以自定義注入module名稱
<template> <p :class="classes.red">red</p> </template> <style module="classes"> .red { color: red; } </style>
注入的類可以通過 useCssModule API 在 setup()
和 <script setup>
中使用:
<script setup> import { useCssModule } from 'vue' // 預設, 返回 <style module> 中的類 const defaultStyle = useCssModule() // 命名, 返回 <style module="classes"> 中的類 const classesStyle = useCssModule('classes') </script>
單檔案元件的 <style>
標籤可以通過 v-bind
這一 CSS 函數將 CSS 的值關聯到動態的元件狀態上:
<script setup> const theme = { color: 'red' } </script> <template> <p>hello</p> </template> <style scoped> p { color: v-bind('theme.color'); } </style>
Vue3.2 setup語法糖、Composition API、狀態庫Pinia歸納總監
到此這篇關於Vue3.2單檔案元件setup的語法糖與新特性的文章就介紹到這了,更多相關Vue3.2單檔案元件setup語法糖內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45