3.0的目標
- 更小
- 更快
- 加強 TypeScript 支持
- 加強 API 設計一致性
- 提高自身可維護性
- 開放更多底層功能
什么是Hooks?
hooks翻譯過來是鈎子的意思,這個可能有一些模糊,簡單點說hooks就是一個函數(可以復用的函數)例如:業務中很難避免的一個問題就是-- 邏輯復用,同樣的功能,同樣的組件,在不一樣的場合下,我們有時候不得不去寫2+次,為了避免耦合我們出現了一些概念(mixin,高級組件,slot插槽)。
上述這些方法都可以實現邏輯上的復用,但是都有一些額外的問題:
mixin的問題:
- 不同的mixin中的方法,屬性可能會相互沖突(命名空間沖突);
- mixin非常多時,會造成數據來源不清晰
HOC的問題:
- 需要在原組件上進行包裹或者嵌套,將會產生非常多的嵌套,調試起來不容易;
- props命名空間沖突(多個高級組件的props沖突)
- props 數據來源不清晰(不知道這個屬性到底是那個高級組件傳遞的)
- 額外的組件實例消耗性能
作用域插槽:
沒有命名沖突和數據來源不清晰的問題,但是創建了額外的組件
所以,hook的出現是划時代的,它通過function抽離的方式,實現了復雜邏輯的內部封裝在vue中的hooks主要是為了邏輯代碼的復用不存在命名沖突,數據來源不清晰的問題減小了代碼體積:因為在打包時候我們用了那些函數就會打包那些不用的不會打包,而且在打包的時候會對函數進行混淆壓縮變得更小沒有this的煩惱,不需要通過this訪問一些內容了。
什么是TypeScript?
其實TypeScript並不是一門新的語言,它是 JavaScript 類型的超集,typeScript那並不是一個新語言,可以理解為加強JavaScript的buff,TypeScript最大的優勢源於強大的類型系統,還有就是在編寫代碼的時候就可以檢測出我們可能因為粗心造成的不必要的錯誤。
為什么要學習TypeScript ?
- 未來趨勢,目前來看發展,和應用趨勢很快
- vue3.0發布后,基本就離不開ts了
- 使用 TypeScript 可以幫助我們防止在編寫 JavaScript 代碼時因為數據類型的轉換造成的意想不到的錯誤。提前幫我們發現代碼出現錯的風險。
- 團隊成員使用 JavaScript 時很容易瞎寫,不受規范約束。但是如果使用TypeScript那大家都不得不遵守規范。
- TypeScript 緊跟 JavaScript 的發展,ES7 、ES8、ES9 相關語言的新特性都支持,比瀏覽器支持的速度更快。
什么樣的項目需要TypeScript ?
- 團隊多人開發的大項目
- 開源項目
- 企業對代碼有高質量要求的項目
如何使用Ts:
Vue3.0 最重要的就是 RFC,即 Function-based API。Vue3.0 將拋棄之前的 Class API 的提案,選擇了 Function API。目前,vue 官方 也提供了 Vue3.0 特性的嘗鮮版本,前段時間叫 vue-function-api,目前已經改名叫 composition-api。
使用官方腳手架Vue-cli創建一個ts項目
npm install -g @vue/cli yarn global add @vue/cli
新的 VueCLI工具允許開發者 使用 TypeScript 集成環境 創建新項目。只需運行 vue create tsvue3demo。然后,命令行會要求選擇預設。使用箭頭鍵選擇 Manually select features。
這樣一個可以使用ts的vue基礎架構就構建完成了
目錄架構
.
├── README.md ├── babel.config.js ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ └── HelloWorld.vue │ ├── main.ts │ ├── router │ │ └── index.ts │ ├── shims-tsx.d.ts 允許你以 .tsx結尾的文件,在 Vue項目中編寫 jsx代碼 │ ├── shims-vue.d.ts 主要用於 TypeScript 識別 .vue 文件 │ ├── store │ │ └── index.ts │ └── views │ ├── About.vue │ └── Home.vue ├── tsconfig.json └── yarn.lock
在這個創建好的目錄中我們打開 HelloWord.vue 文件可以看到不一樣的組件寫法
<template>
<div class="hello">
<h1>{{ msg }}</h1> ... </div>
</template>
<script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator' @Component export default class HelloWorld extends Vue { @Prop() private msg!: string; } </script>
以上的寫法是在vue3.0以前,強化Vue組件使用typeScript的寫法
需要引入:
vue-class-component:強化 Vue 組件,使用 TypeScript/裝飾器 增強 Vue 組件vue-property-decorator:在 vue-class-component 上增強更多的結合 Vue 特性的裝飾器ts-loader:TypeScript 為 Webpack 提供了 ts-loader,其實就是為了讓webpack識別 .ts .tsx文件tslint-loader跟tslint:我想你也會在.ts .tsx文件 約束代碼格式(作用等同於eslint)tslint-config-standard:tslint 配置 standard風格的約束
但是在vue3.0里面廢棄了class component
Vue3.0的用法
Vue3.0還沒有正式發布,但是官方提供了Vue 2.x 能夠提前體驗此API的庫@vue/composition-api
安裝
npm i @vue/composition-api -S
使用
import Vue from 'vue' import VueCompositionApi from '@vue/composition-api' Vue.use(VueCompositionApi)
如果項目是用的 TS,需要使用 createComponent 來定義組件,這樣你才能使用類型推斷,如果沒有使用,可直接拋出一個對象
<template>
<div id="app">
</div>
</template>
<script lang="ts">
import { createComponent } from '@vue/composition-api'
export default createComponent({
...
})
</script>
實例:這是VueConf 2019尤大大在介紹的時候給出的一個例子,改成ts版本
<template>
<div id="app">
<div class="hooks-one">
<h2>{{ msg }}</h2>
<p>count is {{ count }}</p>
<p>plusOne is {{ plusOne }}</p>
<button @click="increment">count++</button>
</div>
<!-- <router-view/> -->
</div>
</template>
<script lang="ts"> import { ref, computed, watch, onMounted, Ref, createComponent } from '@vue/composition-api'
interface Props { name: string } export default createComponent({ props: { name: { type: String, default: 'ssss' } }, components: {}, setup (props: Props, context) { const count: Ref<number> = ref(0) // computed
const plusOne = computed(() => count.value + 1) // method
const increment = () => { count.value++ } // watch
watch(() => count.value * 2, val => { console.log(`count * 2 is ${val}`) }) // 生命周期
onMounted(() => { console.log('onMounted') }) // expose bindings on render context
return { count, plusOne, increment, msg: `hello ${props.name}` } } }) </script>
詳解:setupsetup函數是Vue Function API 構建的函數式寫法的主邏輯,當組件被創建時,就會被調用,函數接受兩個參數,分別是父級組件傳入的props和當前組件的上下文context。context上下文(this的替代者可以理解為),setup 是在組件實例被創建時, 初始化了 props 之后調用,處於 created 前。setup() 和 data() 很像,都可以返回一個對象,而這個對象上的屬性則會直接暴露給模板渲染上下文:
<template> <div id="app"> {{ msg }} {{ count }} </div></template><script lang="ts">import { createComponent } from '@vue/composition-api'export default createComponent({ props: { name: String }, setup (props) { const count: Ref<number> = ref(0) return { msg: `hello ${props.name}`, count } }})</script>
組件 API(Composition API)
組件 API 是 Vue 的下一個主要版本中最常用的討論和特色語法。這是一種全新的邏輯重用和代碼組織方法。當前,我們使用所謂的 Options API 構建組件。為了向 Vue 組件添加邏輯,我們填充(可選)屬性,例如 data、methods、computed等。這種方法的最大缺點是其本身並不是有效的 JavaScript 代碼。你需要確切地知道模板中可以訪問哪些屬性以及 this 關鍵字的行為。在后台,Vue 編譯器需要將此屬性轉換為工作代碼。因此我們無法從自動建議或類型檢查中受益。組件 API 旨在通過將組件屬性中當前可用的機制公開為 JavaScript 函數來解決這個問題。Vue 核心團隊將組件 API 描述為 “一組基於函數的附加 API,可以靈活地組合組件邏輯。” 用組件 API 編寫的代碼更具有可讀性
reactive和ref
reactive(): 轉換響應式對象
ref(): 轉換原始類型為響應式對象
兩者的區別reactive 代理初始化一個對象,ref 只是一個 .value 值,在函數中使用都要一直使用 .value 引着
<template>
<div id="app">
<div class="hooks-one"> {{state.double}} {{state.count}} <p>count is {{ count }}</p>
<button @click="increment">count++</button>
</div>
<!-- <router-view/> -->
</div>
</template>
<script lang="ts"> import { ref, computed, reactive, Ref, createComponent } from '@vue/composition-api'
interface State { count: number, double: number } export default createComponent({ setup (props, context) { const count: Ref<number> = ref(0) const state: State = reactive({ count: 0, double: computed(() => state.count * 2) }) // method
const increment = () => { count.value++ // 需要.value獲取,改變
state.count++ } // expose bindings on render context
return { increment, state } } }) </script>
watch & computed
watch和computed的基本概念與 Vue 2.x 的watch和computed一致,watch可以用於追蹤狀態變化來執行一些后續操作,computed用於計算屬性,用於依賴屬性發生變化進行重新計算。computed返回一個只讀的包裝對象,和普通包裝對象一樣可以被setup函數返回,這樣就可以在模板上下文中使用computed屬性。可以接受兩個參數,第一個參數返回當前的計算屬性值,當傳遞第二個參數時,computed是可寫的。=
生命周期
所有現有的生命周期都有對應的鈎子函數,通過onXXX的形式創建,但有不同的是,destoryed鈎子函數需要使用unmounted代替,刪除了onBeforeCreate和onCreated:
import { onMounted, onUpdated, onUnmounted, createComponent } from '@vue/composition-api';export default createComponent({ setup() { onMounted(() => { console.log('mounted!'); }); onUpdated(() => { console.log('updated!'); }); // destroyed 調整為 unmounted onUnmounted(() => { console.log('unmounted!'); }); },});
參考:
https://zhuanlan.zhihu.com/p/68477600
https://www.yuque.com/vueconf/2019
https://vue-composition-api-rfc.netlify.com/api.html
https://juejin.im/post/5dca71f8f265da4cef191581
https://juejin.im/post/5d836458f265da03d871f6e9
https://segmentfault.com/a/1190000020205747?utm_source=tag-newest