前言
我最一開始是先學的react
,然後也就前段時間開始學習vue
,一開始給我的感受是兩者很相似,react
給我的感覺是靈活,vue
是一種死板的感覺。為什麼有這種感覺呢,react
有一種很強烈的慾望,all in js只要能夠用夠js
寫的,就全用js
寫,所以一切都很靈活,jsx
很酷,高階元件牛逼,es7
的裝飾器也是可以玩的飛起。反觀vue
,搞的.vue單檔案
還是儘量保留原來前端開發的模式,留下了template
、script
、style
三個最基本的東西,其實內部運作應該還是和react
類似。
react
react
看的各種道聽途說的文章,這玩意大概是怎麼玩的呢?簡單的說jsx
被解析成createElement
的方法,裡面傳到引數啊什麼的就是告訴react
怎麼渲染之類,然後方法返回一個虛擬dom
,大概是這麼搞的,具體細節我也不是太懂。
vue
vue
一開始讓我挺暈的,官網的學習教程和一般寫的專案不太一樣,官網教程的例子沒有單檔案,全是在選項物件中加入一個template
屬性,一般的專案開發的都是用的.vue
的單檔案。一開始我是沒太理解.vue
這檔案到底是怎麼玩,只是按著這樣寫,不理解原理好像也能夠基本完成自己想要的效果。
最近看了一些文章以及看了好幾遍官網的api
,官網的api還是很有必要每一個都看一遍的,之前大致看一遍感覺好多東西都沒有見到過,別人程式碼看多了,發現很多沒用的api
還是很強的。下面講講我對vue
的一些理解。
vue
是怎麼玩的呢?每一個vue
元件都是一個Vue
例項,這樣說也不是很準確,應該每一個自己寫的元件都是通過呼叫Vue.extend
繼承Vue
後擴充套件出來的新的類的例項,想一想怎麼定義一個vue
元件,就是呼叫了Vue.component
方法,
// 註冊元件,傳入一個擴充套件過的構造器
Vue.component(`my-component`, Vue.extend({ /* ... */ }))
// 註冊元件,傳入一個選項物件 (自動呼叫 Vue.extend)
Vue.component(`my-component`, { /* ... */ })
// 獲取註冊的元件 (始終返回構造器)
var MyComponent = Vue.component(`my-component`)
一般情況下我們寫的.vue單檔案
暴露出來的就是一個選項物件,這個方法的內部自動呼叫了Vue.extend
。所以.vue單檔案
本質上是vue-loader
去把<template></template>
裡的內容轉成字串形式,塞到<scirpt></script>
裡面的export default {}
的物件裡面的template
去,當然了,這還沒有完,template
屬性裡面的字串也可以說是一種糖,vue
內部是要呼叫Vue.compile
去做一次轉換,最終把template
的值轉換成render
,這個屬性的值是一個方法,這裡就和react
統一了,用是有個同名的函式createElement
去生成Vnode
。所以在選項物件中,可以不給出template
屬性而是給出render
屬性,同時存在template
和render
的時候會忽視template
。
看看官網render
用法:
var getChildrenTextContent = function (children) {
return children.map(function (node) {
return node.children
? getChildrenTextContent(node.children)
: node.text
}).join(``)
}
Vue.component(`anchored-heading`, {
render: function (createElement) {
// create kebabCase id
var headingId = getChildrenTextContent(this.$slots.default)
.toLowerCase()
.replace(/W+/g, `-`)
.replace(/(^-|-$)/g, ``)
return createElement(
`h` + this.level,
[
createElement(`a`, {
attrs: {
name: headingId,
href: `#` + headingId
}
}, this.$slots.default)
]
)
},
props: {
level: {
type: Number,
required: true
}
}
})
看的出來這種直接寫render
比起template
要麻煩的多,所以為了簡化這種寫法就搞出來了一個jsx
寫法,這裡又和react
又統一了。
jsx
用法:
import AnchoredHeading from `./AnchoredHeading.vue`
new Vue({
el: `#demo`,
render: function (h) {
return (
<AnchoredHeading level={1}>
<span>Hello</span> world!
</AnchoredHeading>
)
}
})
一個需求引發的思考
通常我們寫react
和vue
都是一個寫一個元件customComp
,然後在別的元件要用的時候都是直接<customComp/>
寫進去的,但是有的元件就不能這麼做了,比如一個提醒的message
元件,我希望在react
中是這樣呼叫,像是一個工具類函式一般使用:
import message from `message.js`
import React from `react`
class XXXcomponent extends React.Component{
...
componentDidMount(){
message.info({
type:`success`,
text:`hello react!`
})
}
}
在vue
中我希望是這樣的呼叫的:
{
mounted(){
this.$message({
type:`success`,
text:"hello vue!"
})
}
}
在看了一些三方庫的這種元件的實現方式,來回折騰了一段時間,對react
和vue
理解的更深了一些。
vue的實現
先拿vue
說,先寫一個message.vue
的元件檔案,然後在index.js
檔案中把這個message.vue
檔案import
進來,你可以試著列印下這個vue
檔案長得什麼樣,其實前面也分析過了,其實引進來的就是一個選項物件,而且<template></template>
標籤的內容也被弄成了render屬性了,前面也鋪墊過了vue.extend
,這裡把引入的選項物件傳入vue.extend
中就返回了一個擴充套件過的Vue
類了,然後我們手動去new
一個message
的元件例項出來,可以傳入一個propsData
就能把資料傳給到元件內部的prop
中去,列印下例項就會發現定義在.vue
檔案中的data
、prop
之類的都有,這個時候我們只是例項化了一個例項,其實在document
上是找不到這個節點的,只需要最後在例項上呼叫$mount(el)
,就能把例項掛載到document
上去了。直接修改例項上data
裡面定義的值,會發現也是響應的,至此這個message
元件我們能夠手動去控制這個元件了,具體細節該怎麼暴露出api
來個外部呼叫就不說了。
//虛擬碼
import message from `message.vue`
import Vue from `vue`
const Constructor = Vue.extend(message) //擴充套件出一個新的類
const options = {
innerProps:"inner props"
}
const instance = new Constructor({propsData:options}) //建立一個例項,也可以傳給一個props
instance.$mount(document.body) //元件掛在body下
//如果元件內部methods有方法,例項就能直接呼叫
// instance.innerFunction()
react實現
大體上是和vue
類似,有幾個地方有變化,引進來的元件,因為是用class extends React.Component
的形式寫的,看的出來已經是擴充套件過react
後元件類了,直接去new
就能拿到例項了,或者是用React.createElement
傳入元件拿到虛擬dom
。和vue
不同的事,vue
有個$mount
方法幫助掛載元件到指定的位置,在react
中要用到react-dom
裡面的render
方法,傳入前面拿到的虛擬dom
以及要掛載的位置,這個方法會返回這個元件例項,這個時候就可以呼叫元件例項的setState
方法去做一些事情了。
總結
react
、vue
隨便用用帶還是挺簡單的,我的觀點是api文件
只能教會你70%的東西,但是你有了這70%的功力,大部分的東西基本都沒什麼問題,但是文件之外的30%,往往是最難學的,可能需要剝開vue
、react
簡單易用的外表,來回看官方文件,每次都能有新的體會,翻看第三方優秀的元件庫是最佳學習的方案,深入地去理解內部原理才能真正的掌握。
這種元件函式式用法在我的fantastic-carnival(一個部落格系統)中有體現:
其中有一個loadingBar
元件是一個載入條的元件,參考的是iview
元件庫中的vue
實現,同時我用react
也實現了一遍。