Vue.js 是 漸進式
的 JavaScript 框架。什麼是 漸進式
(Progressive) ?就是由淺入深,一步一步的,爲何 Evan You 說 Vue.js 是漸進式的框架呢?javascript
Vue.js 有啥特色呢?html
固然,若是想更全面的瞭解 Vue,對比 React 和 Angular 等框架,能夠看看這裏的 橫向對比前端
參考資料:cn.vuejs.org/v2/guide/vue
Vue2.xjava
Vue 自誕生開始,每個大版本都在進步,相比 Vue1.x
而言,咱們如今使用的 Vue 2.x
效果:react
更小
,vue、vue-router 和 vuex 三個加一塊兒,跟 Vue1.0 的核心庫大小同樣更快
,基本是當前最快的框架,查看測試對比支持SSR 和 原生渲染
參考資料:juejin.im/entry/58102…webpack
Vue3.xgit
相比 Vue2.x
而言,Vue3.x
的設計目標:github
參考資料:img.w3ctech.com/VueConf2019…web
Evan You 爲何制定 Vue3.x
的這些目標呢?可能你們要先了解下 Vue2.x
的現狀。
整體一個觀點:衆口難調!
整體一個原則:沒有絕對好的框架,也沒有絕對差的框架。每一個人仍是從各方面(自身技術能力、團隊技術基礎、上手成本、項目特色)考慮,選擇一款適合本身的框架爲好。
如下是 Evan You 對 Vue 和 React 對比的自我評價:
瞭解詳情:www.zhihu.com/question/30…
One more thing
補充一點 Evan you 對 Vue 和 Angular 對比的自我評價:
瞭解詳情:www.zhihu.com/question/40…
整體評價:Vue2.x 支持顯然跟 React 和 Angular 是有差距的。
如下是 Evan You 對 Ts 的自我評價:
瞭解詳情:www.zhihu.com/question/31…
One more thing
另外 Evan You 當初爲何選擇使用 Flow
,而不是直接上 Ts
?
看這裏:www.zhihu.com/question/46…
首先來看看知乎上的一個帖子,你們討論的熱火朝天:爲何react比vue更適合大型應用?
在我以前的面試中,當問到如何看待 React 和 Vue 這2個框架的時候,也有很多的人的回答是:Vue 適合中小項目,React 適合大型項目!
其實,在回答這個問題以前,你們首先得弄明白 「什麼是中小項目?什麼是大型項目?」 若是這個標準不統一,那你們爭論是沒有意義的。
就比如,什麼是大前端?什麼是前端工程化?這是個人理解
其實業界也沒有太多定義,如下是我的觀點(歡迎指正),大型項目知足其一就行:
1000w
的100人
的500個
的10w行
的除此以外,都應該算做中小項目。
若是按照以上標準劃分大中小型項目的話,你們平時有機會接觸到的大項目有多少呢?
更況且,爲了下降風險,除非沒法拆分,否則通常公司裏面大型項目也會被拆分紅多箇中小項目落地。因此,我要說的是,你們不必從這個角度來劃分一個前端框架,意義不大。
只是從人們的認知裏面,通常認爲的大型項目會出現如下問題,好比:
好了,其實按個人理解,與其說是用項目大小來決定該選擇哪一個框架,不如從自身遇到問題出發衡量下適合本身的框架,由於以上問題不止大型項目的問題,全部項目均可能會遇到。
Vue setup 的思路借鑑了 React hooks 的靈感,同時也解決了 hooks 存在的上面的問題。
參考資料:vue-composition-api-rfc.netlify.com/#comparison…
簡單對比下 React 和 Vue(我的理解和翻閱相關資料,歡迎批量指正,不引戰!輕點噴!):
Vue3.x
的發佈,答案就明瞭(下文會說)!Vue2.x
時代的時候,確定有一些大的團隊會優先考慮穩定性,畢竟歷史上爛尾的例子太多了(近在眼前的 Flow 不就是麼?偷笑)。通過了上面各類對比,咱們回過頭來再看看 Vue3.x 改進:
這實際上是由徹底面向對象OOP的思路,到函數式編程的思想轉變。
只不過提及函數式編程你們看看文檔可能都知道概念,無非業務邏輯都是一個個函數實現嘛!可是,真讓你在項目裏自由發揮寫那麼多函數的時候,你該怎麼寫?(這可能也是你們以爲 React 不太容易上手的以一個緣故吧,喜歡被 Vue 安排的明明白白!)
因而結合着 Vue2.x 裏面的 Options API,將之前徹底按照AOP模式的Options API,細粒度拆分紅細小的函數,而後統一放到 setup
這一個入口函數中調用!雞賊!佩服!
這樣作的3個好處:
Vue2.x
中各個函數的功能,作到兼容tree-shaking
可謂:一石三鳥
!
下面以示例的形式來解釋下這個概念。
好比 Vue2.x 時對於一個獨立組件:
開始只有簡單的鼠標處理邏輯。
export default {
data() {
return {
x: 0,
y: 0
}
},
mounted() {
window.addEventListener('mousemove', this.update)
},
methods: {
update(e) {
this.x = e.pageX
this.y = e.pageY
}
},
destroyed() {
window.removeEventListener('mousemove', this.update)
}
}
複製代碼
以上會存在什麼問題呢?舉例來講明:
隨着時間的推移,這個組件可能會發展成以下的模樣!
export default {
data() {
return {
x: 0,
y: 0,
a: 0,
b: 0,
c: 0,
d: 0,
e: 0,
f: 0,
g: 0,
h: 0,
i: 0,
j: 0,
k: 0,
l: 0,
m: 0,
n: 0 // 算了寫不下去了。。。總之 data 可能會有不少
}
},
mixins: [
a,
b,
c,
d,
e,
f // 算了,寫不下去了,總之爲了拆分代碼,mixins 已經讓我寫到吐了
],
mounted() {
window.addEventListener('mousemove', this.update)
// TODO 接下來可能會有一堆頁面渲染完成的邏輯在這裏哦
// 這裏是業務邏輯1
// if / else if / else
// 下面是業務邏輯2
// while
// 哎呀全部的事情,都須要在頁面渲染完去作呀,沒辦法
// switch
// 算了,寫不下去了。。。
// 跑路。。。
},
methods: {
update(e) {
this.x = e.pageX
this.y = e.pageY
},
// 下面有一堆方法等着你哦
method1() {
// 預留着,方法只能放到 methods 對象下啊
},
method2() {
// 張三的註釋
// 一堆邏輯
},
method3() {
// ... 跑路了。。。
}
},
destroyed() {
window.removeEventListener('mousemove', this.update)
}
}
複製代碼
你們看出來上面的代碼的問題了麼?由於你們必須在 Vue 規定的條條框框裏面寫東西,因此,尤爲初學者,會把一個簡單的組件,寫到簡直沒法直視的地步!
那你可能要說了,以上代碼是有不少解決辦法的呀,好比下面2種常見的優化方案:
一、將這個文件拆分紅多個子組件或者模塊
好比:若是按模塊拆分,能夠把 data
拆分紅一個js文件,methods
拆分紅一個 js 文件,等等。這麼作只是至關於把一堆代碼打散而已,代碼連貫性、可維護性方面,變得更糟了。
再好比:拆分紅多個子組件,每一個子組件實現一塊邏輯!(這是強拆!)你們拆分組件的原則,確定不是基於代碼量去拆的吧!因此,這會讓業務模塊,變得支離破碎,難以理解和維護。
二、使用 mixins
提取公共代碼
mixins
解決的是公共的代碼混入複用,若是隻是一個組件過於龐大,你拆分到 mixins 多個文件中,有啥意義呢?跟上面的強拆有啥區別?
更況且,即使有複用的代碼,若是一個文件中引入 10個以上的 mixin 文件,裏面的 data 可能會覆蓋,methods 可能會覆蓋,你知道哪一個生效了?template 使用的變量,你知道來自哪裏?
對於上面的示例,Vue3.x 的解決辦法
定義獨立文件 mouse.js
這個文件就只處理鼠標事件!業務和代碼邏輯都在一塊兒,好理解,易於維護。
import { ref, onMounted, onUnmounted } from 'vue'
export function useMousePosition() {
const x = ref(0)
const y = ref(0)
function update(e) {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}
複製代碼
main.vue
引入文件
這裏的代碼量也變的不多,很清晰。
import { useMousePosition } from './mouse'
export default {
setup() {
const { x, y } = useMousePosition()
// other logic...
return { x, y }
}
}
複製代碼
示例參考:vue-composition-api-rfc.netlify.com/#logic-extr…
若是遇到不一樣的業務模塊,就單獨到獨立文件或者模塊處理,而後引入便可,好比:
(下面的邏輯若是在 vue2.x 中還真不太好處理!)
export default {
setup () {
// Network
const { networkState } = useNetworkState()
// Folder
const { folders, currentFolderData } = useCurrentFolderData(networkState)
const folderNavigation = useFolderNavigation({ networkState, currentFolderData })
const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData)
const { showHiddenFolders } = useHiddenFolders()
const createFolder = useCreateFolder(folderNavigation.openFolder)
// Current working directory
resetCwdOnLeave()
const { updateOnCwdChanged } = useCwdUtils()
// Utils
const { slicePath } = usePathUtils()
return {
networkState,
folders,
currentFolderData,
folderNavigation,
favoriteFolders,
toggleFavorite,
showHiddenFolders,
createFolder,
updateOnCwdChanged,
slicePath
}
}
}
複製代碼
參考代碼:vue-composition-api-rfc.netlify.com/#code-organ…
看了以上代碼有啥感想?我本身的感覺:
Vue2.x 寫法:
import { Component, Prop, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
@Prop() private message!: string;
data (): object {
// this.message
}
}
複製代碼
Vue3.x 寫法:
import { defineComponent } from 'vue'
export default defineComponent({
props: {
message: String
},
setup(props, context) {
// setup 中沒法使用 this 關鍵詞
// props.message
// context.attrs
// context.slots
// context.emit
}
})
複製代碼
對比下,至少寫法上更簡單,並且不用在使用那麼多的 裝飾器
了!
再回過頭來看看 Evan You 對 Vue3.x 的目標定義:
上文已說明
上文已說明
上文已說明
更小
對比了 vue@3.0.0-alpha.8
和 vue@2.6.11
這2個版本的未壓縮版本的文件大小:
單純從這2個獨立的版本看,3.0還變大了!
因此,我的認爲,真正要能變小,可能仍是要放到工程化體系中,依賴編譯器,好比:webpack,而後基於 3.0 這種函數式編程更好 tree shaking 的機制,最終打包編譯後的效果而言。
更快
Vue3.x 如下重大變化:
Object.defineProperty()
換成了 new Proxy()
參考地址:img.w3ctech.com/VueConf2019…
理論上性能上確定要比以前好(至少 Proxy 就更高效一些),可是這個目前還很差驗證,相信正式 Release 後續官方也會給出一些數據,同時圈內確定也會有不少測試結果出爐。
開放更多底層功能
這個目前還不太清楚,等官方出爐吧。
(本文完)