作者:流_星
轉發鏈接:
https://juejin.im/post/5ea97600f265da7b983b9e76
前言
2020註定是不平凡的一年,無論是疫情的橫空出世,還是世界局勢的激烈動盪,抑或是股市的跌宕起伏,我相信很多國人都會有一種慶幸我是中國人的深刻感悟。作為一名技術宅,除了疫情,更多的還是雨女無瓜,隨著Vue3.0 Beta的推出,大家都爭先恐後的嚐了鮮,筆者也不例外,經過一番研究,覺得Vue3也的確存在它獨特的魅力,也應該寫一篇博客方便還沒有體驗的朋友能夠快速對其有一個大體的認知。
開始
此文默認你已熟悉Vue2.x相關知識
環境搭建
相關庫版本
- Vue-Cli 4.x
- Vue 3.0.0-beta.1
- Vue-Router 4.0.0-alpha.7
具體步驟如下:
- 使用VueCli創建一個Vue基礎項目:vue create project
- 在項目中,執行升級命令:vue add vue-next
項目目錄結構如下:
進行完以上操作無誤之後基本環境就已經搭建完畢。
配置路由
- 項目中執行npm install [email protected] -S
按照一般規範,在src目錄下新建router文件夾,並在router文件夾中新建index.js文件。
index.js內容:
<code>import
{ createRouter, createWebHashHistory }from
'vue-router'
;import
Homefrom
'../components/home'
const
routes = [ {path
:'/'
,redirect
:'/home'
}, {path
:'/home'
,component
: Home} ]export
default
createRouter({history
: createWebHashHistory(), routes }) 複製代碼/<code>
基本的路由配置沒有太大改變,大多數情況下你只需要關注routes中路由規則編寫。接下來,我們需要在main.js中接入router。
main.js:
<code>import
{ createApp }from
'vue'
;import
Appfrom
'./App.vue'
import
routerfrom
'./router'
;const
app = createApp(App); app.use(router); app.mount('#app'
); 複製代碼/<code>
不同於我們之前採用new Vue()創建實例的方式,Vue3在這裡進行了改變;不僅如此,我們不難發現,安裝路由的方式也由之前的Vue.use(Router)變成如上方式,同理對於Vuex的接入也是大同小異,筆者這裡就不過多贅述了。
App.js
<code><
template
><
div
id
="app"
><
router-view
>router-view
>div
>template
> 複製代碼/<code>
基礎語法初探
setup
setup功能是新的組件選項,它充當在組件內部使用Composition API(新特性)的入口點;創建組件實例時,在初始道具解析後立即調用。在生命週期方面,它在beforeCreate掛接之前被調用。
一般來說,按照我們之前常規的寫法,我們在對需要使用變量、計算屬性的時候,我們會習慣性的寫上:
home/index.vue
<code><
template
><
div
class
='home'
><
div
>{{count}}div
><
div
>{{foo}}div
>div
>template
><
script
>
import
{ ref }from
'vue'
export
default
{name
:'home'
, data() {return
{count
:0
} },computed
: { foo() {return
this
.count +1
; } } }; 複製代碼/<code>
兩者是需要被分類到各自的對象中,在同等功能實現上來說,Vue3的實現如下:
<code><
template
><
div
class
='home'
><
div
>{{count}}div
><
div
>{{foo}}div
>div
>template
><
script
>
import
{ ref, computed }from
'vue'
export
default
{name
:'home'
, setup(props, context) {const
count = ref(0
)const
foo = computed(()
=> count.value +1
)return
{ count, foo } } };script
> 複製代碼/<code>
看到這種語法你是不是懵了,不用慌,這部分著重介紹setup這個入口函數,具體內部語法可以先不用在意,後面都會進行對應性一一講解。
setup接收兩個重要參數:
- props:這個自然不用多提了,等同於vue2的props,在這個地方我們需要注意的地方是,我們不能對這個參數進行解構,如果使用解構會使它失去響應性。例如下面代碼就會讓props傳過來的值失去響應性:
<code>export
default
{props
: {name
:String
}, setup({ name }) { watchEffect(()
=> {console
.log(`name is: `
+ name) }) } } 複製代碼/<code>
- context:其實這個參數我們也是比較熟悉的,它提供了一個上下文對象,該對象公開了先前this在2.x API中公開的屬性的選擇性列表,它僅包含三個屬性(attrs、slots、emit),舉個栗子:
<code>setup
(props, context) {context
.attrs
context
.slots
context
.emit
} 複製代碼/<code>
看完代碼,我們基本可以理解為setup函數就是我們整個組件各項邏輯關係以及操作的入口了,在Vue3中,我們使用不同api的方式都是採用導入的形式,這就相當於我們有了更大的操作空間,有了更大的自由性。
雖然說Vue3向下兼容Vue2,但是這裡其實我們需要注意的是,我們應該儘量避免2.x和setup函數的混用,這將會導致一些問題。
reactive
取得一個對象並返回原始對象的反應式代理。這等效於2.x的Vue.observable()。
對這個api用法,筆者用代碼講解會比較好理解:
<code><
template
><
div
class
='home'
><
div
>{{name}}div
>div
>template
><
script
>
import
{ reactive }from
'vue'
export
default
{name
:'home'
, setup() {const
obj = reactive({name
:'流星啊'
}) obj.name ='bilibili'
;return
obj; } };script
> 複製代碼/<code>
相信大家已經看出來端倪,沒錯,這個api就是單純的把一個對象變得可響應。
ref
接受一個內部值並返回一個反應性且可變的ref對象。ref對象具有.value指向內部值的單個屬性。
在這裡我估計有小夥伴就要問了,這不就是2.x裡的ref嗎,不不不,在3.x它跟那個種在標籤上的ref沒有半點關係,也和$refs沒有任何關係,對於新的類似於2.x的獲取dom的方式請看模板引用部分。
同樣,舉個栗子:
<code><
template
><
div
class
='home'
><
div
>{{count}}div
>div
>template
><
script
>
import
{ ref }from
'vue'
export
default
{name
:'home'
, setup() {const
count = ref(0
); count.value++;console
.log(count.value);return
{ count }; } };script
> 複製代碼/<code>
這裡也有一個注意點,你如果想要修改使用ref構造出來的變量,只能對xxx.value進行修改,同理你想要在js中訪問它的值必須使用xxx.value,直接對count進行賦值如count++,這種寫法會報錯。
在這裡估計又有小夥伴要問了,那為啥在template模板中使用{{count}}訪問的時候不用加.value,這裡其實你在使用插值表達式的時候,它內部會自動展開,所以我們直接用就行了。
如果說我們把reactive和ref結合起來用會有怎樣的奇淫巧計呢,繼續舉個栗子:
<code>constcount
= ref(0
) const state = reactive({count
}) console.log(state.count
) state.count
=1
console.log(count
.value) 複製代碼/<code>
當ref被訪問或作為反應對象的屬性進行更改時,它會自動展開為內部值,因此其行為類似於普通屬性。
computed
這個api也類似2.x,可以使用getter、setter,話不多說,上代碼:
<code>const
count =ref
(1
)const
plusOne = computed(() => count.value
+1
) console.log(plusOne.value
) plusOne.value
++ 複製代碼/<code>
在這裡我們不難發現,它的訪問方式也等同於ref,也是需要採用xxx.value,與此同時呢,如果你想要修改一個計算屬性的值,你必須為他設置setter,並對相應的依賴進行修改。廢話少說,看碼:
<code>const
count =ref
(1
)const
plusOne = computed({get
: () => count.value
+1
,set
: val => { count.value
= val -1
} }) plusOne.value
=1
console.log(count.value
) 複製代碼/<code>
readonly
意如其名,顧名思義,就是構造一個只能訪問的屬性,這個玩意它針對的很強,也就是無論你這個對象嵌套有多深,被他包裝後的對象一定是隻能讀,其實就是相當於一個代理:
<code>const
re = reactive({count:0
})const
readonlyRe =readonly
(re); readonlyRe.count++; 複製代碼/<code>
watchEffect
對於這個屬性呢,你可以拿它跟2.x的watch對象相比較了,沒錯他就是來監聽的。
<code>const
count = ref(0
) watchEffect(()
=>console
.log(count.value)) setTimeout(()
=> { count.value++ },100
) 複製代碼/<code>
總而言之,他會收集傳入函數的依賴,一旦依賴發生發生改變,他就會重新調用你傳進來的函數,用過react hooks的童靴可能會說,這玩意怎麼這麼像useEffect,其實Vue3也的確借鑑了react一些不錯的設計,所以,大家也不要覺得抄襲不抄襲的,框架終究是為用戶服務,好的設計自然應該值得借鑑,就像react也有借鑑Vue的一些優點對自身進行優化。
接下來我們繼續刨析這個api。調用這個api的同時,它會返回一個用於暫停句柄的函數,我們可以顯式調用它用於的停止當前監聽,並且對於傳入給watchEffect的回調函數,這個api在觸發調用的時候會傳入一個用於註冊無效回調的函數onInvalidate。具體例子如下:
<code>const
stop = watchEffect(onInvalidate
=> {const
token = performAsyncOperation(id.value); onInvalidate(()
=> { token.cancel(); }) }) stop(); 複製代碼/<code>
如果我們註冊了無效回調方法,那麼在這個依賴已經變化但是異步請求還未完成的時候,它內部就會幫我們調用我們註冊的無效回調。
生命週期函數
這裡給一個與2.x的對比:
- beforeCreate (vue3棄用) -> 使用 setup()
- created (vue3棄用) -> 使用 setup()
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeDestroy -> onBeforeUnmount
- destroyed -> onUnmounted
- errorCaptured -> onErrorCaptured
使用示例:
<code>import
{ onMounted, onUpdated, onUnmounted }from
'vue'
const MyComponent = { setup() { onMounted(()
=> {console
.log('mounted!'
) }) onUpdated(()
=> {console
.log('updated!'
) }) onUnmounted(()
=> {console
.log('unmounted!'
) }) } } 複製代碼/<code>
模板引用
在看完前面ref這個api的介紹之後,很多小夥伴肯定也會疑惑,那我要獲取dom怎麼辦,這個Vue3也有的,放寬心,聽筆者繼續娓娓道來。
<code><
template
><
div
class
='home'
><
div
ref
="dom"
>div
>div
>template
><
script
>
import
{ ref, onMounted }from
'vue'
export
default
{name
:'home'
, setup() {const
dom = ref(null
) onMounted(()
=> {console
.log(dom.value); })return
{ dom } } };script
> 複製代碼/<code>
從代碼中我們可以發現,現在這種訪問dom的方式和之前區別在於,我們需要顯示設定一個響應性變量,然後再在模板中使用之前我們耳熟能詳的方式ref='xxx'來進行設定。
結尾
聽完筆者的敘述,你有沒有對Vue3有一種躍躍欲試的想法呢。
如有發現筆者表述不當的地方,請在評論區戳筆者哦,感激不盡。
推薦Vue學習資料文章:
《深入淺出通過vue-cli3構建一個SSR應用程序【實踐】》
《聊聊昨晚尤雨溪現場針對Vue3.0 Beta版本新特性知識點彙總》
《【新消息】Vue 3.0 Beta 版本發佈,你還學的動麼?》
《Vue + Koa從零打造一個H5頁面可視化編輯器——Quark-h5》
《深入淺出Vue3 跟著尤雨溪學 TypeScript 之 Ref 【實踐】》
《手把手教你深入淺出vue-cli3升級vue-cli4的方法》
《Vue 3.0 Beta 和React 開發者分別槓上了》
《手把手教你用vue drag chart 實現一個可以拖動 / 縮放的圖表組件》
《Vue3 嚐鮮》
《手把手讓你成為更好的Vue.js開發人員的12個技巧和竅門【實踐】》
《2020 年,Vue 受歡迎程度是否會超過 React?》
《手把手教你Vue解析pdf(base64)轉圖片【實踐】》
《
推薦 8 個漂亮的 vue.js 進度條組件》《手把手教你Vue之父子組件間通信實踐講解【props、$ref 、$emit】》
《深入淺出Vue3 的響應式和以前的區別到底在哪裡?【實踐】》
《乾貨滿滿!如何優雅簡潔地實現時鐘翻牌器(支持JS/Vue/React)》
《基於Vue/VueRouter/Vuex/Axios登錄路由和接口級攔截原理與實現》
《手把手教你D3.js 實現數據可視化極速上手到Vue應用》
《吃透 Vue 項目開發實踐|16個方面深入前端工程化開發技巧【上】》
《吃透 Vue 項目開發實踐|16個方面深入前端工程化開發技巧【中】》
《吃透 Vue 項目開發實踐|16個方面深入前端工程化開發技巧【下】》
作者:流_星
轉發鏈接:
https://juejin.im/post/5ea97600f265da7b983b9e76