不知不覺的VUE3.0釋出已經很久了。
在B站上看了教學視屏 瞬間勾起的我濃厚的學習興趣。視屏的内容講解的很棒這裡推薦一波。
https://www.bilibili.com/video/BV1yK4y1M7Fz?p=8&spm_id_from=pageDriver
亮點1
Vue 3全新的Web開發建構工具Vite
Vite是Vue的作者尤雨溪開發的Web開發建構工具,它是一個基于浏覽器原生ES子產品導入的開發伺服器,在開發環境下,利用浏覽器去解析import,在伺服器端按需編譯傳回,完全跳過了打包這個概念,伺服器随啟随用。同時不僅對Vue檔案提供了支援,還支援熱更新,而且熱更新的速度不會随着子產品增多而變慢。在生産環境下使用Rollup打包。
Vite具有以下特點:
快速的冷啟動即時熱子產品更新(HMR,Hot Module Replacement)真正按需編譯Vite是在推出Vue 3的時候開發的,目前僅支援Vue 3.x,這意味着與Vue 3不相容的庫也不能與Vite一起使用。
與Vue CLI類似,Vite也提供用npm或者yarn來生成項目結構的方式。選擇一個目錄,打開指令提示視窗,依次執行下面的指令建構腳手架項目,并啟動項目。
用npm指令建立一個vite的項目
npm init vite-app <project-name>
cd <project-name>
npm install
npm run dev
如果使用yarn,則依次執行下面的指令:
yarn create vite-app <project-name>
cd <project-name>
yarn
yarn dev
由于Vite使用了浏覽器原生的ES子產品導入功能,但IE 11并不支援ES的子產品導入,是以基于Vite開發項目,浏覽器不能使用IE11,其他主流的浏覽器均支援ES子產品的子產品功能。
我建立了一個項目 結構如下
可以發現,Vite生成的腳手架項目的目錄結構與Vue CLI生成的項目目錄結構很類似,确實是這樣的,而且開發方式也基本相同。不過Vite項目的預設配置檔案是vite.config.js,而不是vue.config.js。
package.json檔案的内容如下所示:
{
"name": "webapp-vue3",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"dependencies": {
"vue": "^3.0.4"
},
"devDependencies": {
"vite": "^1.0.0-rc.13",
"@vue/compiler-sfc": "^3.0.4"
}
}
這裡與Vue CLI不同地方在這裡:
"dev": "vite",
"build": "vite build"
體驗了一波非常棒,基本上都是秒啟動,改動代碼以後也是秒更新
Vue 3采用Proxy資料劫持
- Vue 2.x 利用 Object.defineProperty(),并且把内部解耦為 Observer, Dep, 并使用 Watcher 相連
- Vue 在 3.x 版本之後改用 Proxy 進行實作
那麼他們之前有什麼優缺點呢?
1、Object.defineProperty() 的問題主要有三個:
- 不能監聽數組的變化
- 必須周遊對象的每個屬性
- 必須深層周遊嵌套的對象
-
數組的這些方法是無法觸發set的:push, pop, shift, unshift,splice, sort, reverse.
Vue 把會修改原來數組的方法定義為變異方法 (mutation method)
非變異方法 (non-mutating method):例如 filter, concat, slice 等,它們都不會修改原始數組,而會傳回一個新的數組。
Vue 的做法是把這些方法重寫來實作數組的劫持。
- 使用 Object.defineProperty() 多數要配合 Object.keys() 和周遊,,于是多了一層嵌套
Object.keys(obj).forEach(key => {
Object.defineProperty(obj, key, {
// ...
})
})
當一個對象為深層嵌套的時候,必須進行逐層周遊,直到把每個對象的每個屬性都調用 Object.defineProperty() 為止。 Vue 的源碼中這樣的邏輯----walk 方法.
2、Proxy:
Proxy 對象用于定義基本操作的自定義行為(如屬性查找,指派,枚舉,函數調用等)。
- 針對對象:針對整個對象,而不是對象的某個屬性
- 支援數組:不需要對數組的方法進行重載,省去了衆多 hack
- 嵌套支援: get 裡面遞歸調用 Proxy 并傳回
-
其他
針對對象
不需要對 keys 進行周遊。這解決Object.defineProperty() 的第二個問題.Proxy 是針對整個 obj 的。是以 obj 内部包含的所有的 key ,都可以走進 set。(省了一個 Object.keys() 的周遊)
let obj = {
name: 'Eason',
age: 30
}
let handler = {
get (target, key, receiver) {
console.log('get', key)
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
console.log('set', key, value)
return Reflect.set(target, key, value, receiver)
}
}
let proxy = new Proxy(obj, handler)
proxy.name = 'Zoe' // set name Zoe
proxy.age = 18 // set age 18
嵌套支援
Proxy 也是不支援嵌套的,這點和 Object.defineProperty() 是一樣的。是以也需要通過逐層周遊來解決。Proxy 的寫法是在 get 裡面遞歸調用 Proxy 并傳回
let obj = {
info: {
name: 'eason',
blogs: ['webpack', 'babel', 'cache']
}
}
let handler = {
get (target, key, receiver) {
console.log('get', key)
// 遞歸建立并傳回
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], handler)
}
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
console.log('set', key, value)
return Reflect.set(target, key, value, receiver)
}
}
let proxy = new Proxy(obj, handler)
// 以下兩句都能夠進入 set
proxy.info.name = 'Zoe'
proxy.info.blogs.push('proxy')
其它方面
優勢:Proxy 的第二個參數可以有 13 種攔截方法,比 Object.defineProperty() 要更加豐富,Proxy 作為新标準受到浏覽器廠商的重點關注和性能優化,相比之下 Object.defineProperty() 是一個已有的老方法。
劣勢:Proxy 的相容性不如 Object.defineProperty() (caniuse 的資料表明,QQ 浏覽器和百度浏覽器并不支援 Proxy,這對國内移動開發來說估計無法接受,但兩者都支援 Object.defineProperty()),不能使用 polyfill 來處理相容性
Vue3 的新特性(二) —— Composition-Api
Composition API
: 一組低侵入式的、函數式的 API,它使我們能夠更靈活地「組合」元件的邏輯。Composition API 的靈感來自于 React Hooks ,是比 mixin 更強大的存在。它可以提高代碼邏輯的可複用性,進而實作與模闆的無關性;同時函數式的程式設計使代碼的可壓縮性更強。另外,把 Reactivity 子產品獨立開來,意味着 Vue3.0 的響應式子產品可以與其他架構相組合。
如上圖,在較大元件的編寫中,
Composition-Api
可以把複雜元件的邏輯抽地更緊湊,而且可以将公共邏輯進行抽取。
setup() 函數
是 Vue3 中的新增内容。它為基于
setup()
Composition API
的新特性提供了統一的入口。
在Vue3中,定義
、
methods
watch
computed
資料 等都放在了
data
setup()
函數中
注意:在
函數中通路不到Vue的
setup()
執行個體
this
1. 執行時機
函數會在
setup()
生命周期之前執行。
created()
import { ref } from "vue";
// setup 在init執行的
export default {
name: 'HelloWorld',
setup () {
console.log('setup')
const name = ref('啊sir')
// onMounted(()=>{
// alert('1111')
// })
return {
name
}
},
mounted () {
console.log('mounted')
},
beforeCreate () {
console.log('beforeCreate')
},
created () {
console.log('created')
}
}
接收props資料(由于setup沒有this,是以通路内部屬性隻能傳遞參數)
函數的第一個參數是
setup()
,元件接收的
props
資料可以在
props
setup()
函數内通路到
context 是 setup() 的第二個參數,它是一個上下文對象,可以通過 context 來通路Vue的執行個體 this 。
setup(props,context) {
console.log(this)
console.log(context)
}
1. reactive()
reactive()
函數接收一個普通的對象,傳回出一個響應式對象。
在Vue2.x的版本中,我們隻需要在
中定義一個資料就能将它變為響應式資料,在 Vue3.0 中,需要用
data()
函數或者
reactive
來建立響應式資料。
ref
setup() {
// 建立響應式對象
const state = reactive({
count:0
});
// 将響應式對象return出去,暴露給模闆使用
return state;
}
使用響應式對象
<p>目前的count的值為:{{count}}</p>
<button @click="count++">點選增加count< button>
2. ref()
ref() 函數可以根據給定的值來建立一個響應式的資料對象,傳回值是一個對象,且隻包含一個 .value 屬性。
用 ref 建立響應式對象
setup() {
// 建立響應式對象
const count = ref(0);
return {
count
}
}
<p>目前的count的值為:{{count}}</p>
<button @click="count++">點選增加count</button>
ref 的注意事項
在 setup() 函數内,由 ref() 建立的響應式資料傳回的是對象,是以需要用 .value 來通路;