新增:哈哈,最近又推出了 vue 的文章,在這裏放個連接~
手把手教你從零寫一個簡單的 VUEjavascript
感謝有人看我扯技術,這篇文章主要介紹最近很是火的vue2前端框架的特色和vue2+vuex2+webpack2各類2的先後端同構渲染架構搭建流程,最後會附上代碼,文章想到啥寫啥,若是存在錯誤,或者你們有什麼意見建議,歡迎你們指出來css
vue2出來以後,基本上逛論壇逛技術羣都能看到各類文章,各類討論 ,一時間你們都在學習vue2了 ,我今年年初就開始接觸vue,最初也是在react ,angular,vue 之中對比選擇,最終選擇了vue,由於其對前端比較友好(使用正常的模板,而不是JSX)、概念及學習成本相對簡單(對於團隊開發,引入技術必需要考慮其學習成本),下面介紹下我理解的vue2和vue1的不一樣之處 ,若有不足,歡迎補充:html
1.引入了virtual Dom
前端
在vue1中,數據和視圖的綁定流程是經過
Object.defineProperty
將數據轉化爲getter/setter
,getter/setter
中加入watcher
,當對數據進行操做的時候,setter
的watch
被觸發從新計算,而後更新和這個數據有關聯的dom元素,這就是vue1的數據驅動視圖原理
在vue2中,數據的綁定和觸發和vue1相同,基本原理都是經過Object.defineProperty
對數據加入'鉤子',以便在數據發生變化的時候得以響應,而在響應以後,不像vue1同樣直接更新dom元素,而是放入virtual Dom
中,進行比對計算,而後對dom元素作相應的處理。下面是vue1和vue2的響應流程對比vuevue:
javavue2:
node關於
virtual Dom
: 虛擬dom最初是在react上面認識的,其實作的事情就是在js內存中創建好dom的結構,而後再更新虛擬dom時作差別比對,將差別的地方真正更新到頁面中,作到最小化頁面的渲染。固然,也不是說對於全部情景,虛擬dom的性能都是最好的,畢竟比起直接操做dom元素,他仍是須要在內存中進行計算,所以對於少許的元素更新,可能其性能比起直接操做dom元素要差。固然虛擬dom的引入,不僅是在性能方面的考慮,虛擬dom能夠帶來編程的變化,好比你可使用render
方法直接建立新的節點,虛擬dom也是vue2能夠進行服務端渲染的關鍵,因爲虛擬dom是在內存重點,vue2的ssr能夠將虛擬dom直接生成html的字符串,從而實現ssr。除此以外,vue2 從模板到 virtuel-DOM 的編譯階段使用了一些高階優化:react(1). 它會檢測出靜態的
class
名和attributes
這樣它們在初始化渲染以後就永遠都不會再被比對。
(2). 它會檢測出最大靜態子樹 (就是不須要動態性的子樹) 而且從渲染函數中萃取出來。這樣在每次重渲染的時候,它就會直接重用徹底相同的virtual nodes
同時跳過比對。
這些高階優化一般只會在使用JSX
時經過Babel plugin
來作,可是 vue2 即便在使用瀏覽器內的編譯器時也能作到。webpack
2.組件事件傳遞機制的改變,組件數據雙向綁定的去除git
vue2組件廢除了
$dispath/$broadcast
父子組件的事件傳播方式,廢除了過濾器,props
參數等的數據雙向綁定以及處理功能,說明做者但願使用者經過創建全局的狀態管理,事件管理機制,經過使用事件中心,容許組件自由交流,不管組件處於組件樹的哪一層,將狀態管理集中在一塊兒處理,官方提供的vuex
就是用來幾種管理狀態的。
3.服務端渲染 ssr:server-side-render
因爲
virtual dom
的引入,使得vue的服務端渲染成爲了可能,下面是官方vue-server-renderer
提供的渲染流程圖:能夠看出vue的
server-side-render
有三部分組成,一部分是頁面的源碼(source),還有node層的渲染部分和瀏覽器端的渲染部分。
source
分爲兩種entry point
,一個是前端頁面的入口client entry
,主要是實例化Vue對象,將其掛載到頁面中;另一個是後端渲染服務入口server entry
,主要是控服務端渲染模塊回調,返回一個Promise對象,最終返回一個Vue對象(通過測試,直接返回Vue對象也是能夠的);前面的
source
部分就是業務開發的代碼,開發完成以後經過webpack
進行構建,生成對應的bundle,這裏再也不贅述client bundle
,就是一個可在瀏覽器端執行的打包文件;這裏說下server bundle
, vue2提供vue-server-renderer
模塊,模塊能夠提供兩種render:rendererer/bundleRenderer
,下面分別介紹下這兩種render。
renderer
接收一個vue對象 ,而後進行渲染,這種對於簡單的vue對象,能夠這麼去作,可是對於複雜的項目,若是使用這種直接require一個vue對象,這個對於服務端代碼的結構和邏輯都不太友好,首先模塊的狀態會一直延續在每一個請求渲染請求,咱們須要去管理和避免此次渲染請求的狀態影響到後面的請求,所以vue-server-renderer
提供了另一種渲染模式,經過一個bundleRenderer
去作渲染。
bundleRenderer
是較爲複雜項目進行服務端渲染官方推薦的方式,經過webpack以server entry
按照必定的要求打包生成一個server-bundle
,它至關於一個能夠給服務端用的app的打包壓縮文件,每一次調用都會從新初始化 vue對象,保證了每次請求都是獨立的,對於開發者來講,只須要專一於當前業務就能夠,不用爲服務端渲染開發更多的邏輯代碼。
renderer生成完成以後,都存在兩個接口,分別是renderToString
和renderToStream
,一個是一次性將頁面渲染成字符串文件,另一個是流式渲染,適用於支持流的web服務器,能夠是請求服務的速度更快
4.除了上面說的那些不一樣,vue2在生命週期管理,動畫機制等地方都與vue有些差異,具體請瀏覽migration
相對於 vue2和vue 較大改動,vue的狀態管理工具 vuex的改動不是很大,底層改動因爲時間關係尚未來得及細究,可是在使用方面多了幾個 Helper,利用ES6的展開函數能夠更加方便的使用
state,getters,mutations,actions
。下面簡單介紹下vuex各個部分的概念
state
是一個全局的狀態存儲,數據會存儲在其中,vue組件能夠直接訪問其中的值,可是隻能夠讀,不能夠進行寫操做getter
,有些時候咱們須要對獲取的數據進行加工,而不是直接獲取state中的數據,這時候能夠經過getter定義函數,返回對應的數據mutations
是vuex中惟一一個能夠修改數據的地方,mutations
能夠定義事件函數,在vue組件中能夠經過commit發射事件,調用函數。須要注意的是,mutations
中的操做必須是同步的,不能夠存在異步操做的狀況。actions
和mutation
比較類似,不一樣的是actions中不直接修改state,而是經過commit調用mutations修改數據,並且actions中能夠存在異步處理邏輯
webpack2
和webpack
對比,有如下的新特性:
- ES6 Modules : webpack 2 已經支持原生的 ES6 的模塊加載器了,這意味着 webpack 2 可以理解和處理 import和export了,而不用把他們轉化成 CommonJS 來處理了。
- 用 ES6 來作代碼拆分 : ES6 的模塊加載器定義了System.import這一個方法,System.import可以在運行時動態加載 ES6 模塊。
- 混合使用 ES6 和 AMD 和 CommonJS (Mixing ES6 with AMD and CommonJS)
更加具體的新特性能夠瀏覽連接地址
好了,前面扯了那麼多東西,估計沒什麼人看,咱們仍是迴歸題目,開始敲代碼吧,哈哈,接下來我會使用vue2 + vuex2 + webpack2 搭建一個簡單的 ssr項目,可以直出頁面,還可以保存成靜態文件。雖然官方頁面響應的實例vue-hackernews-2.0,可是若是一開始把代碼下下來,仍是不太容易理解的,因此我參考其例子,從零開始搭建項目,源碼在文章的最後
首先固然是使用
npm init
新建一個項目
而後往package.json
中寫入下列依賴
而後運行
npm i
,而後去上個廁所,喝杯茶也行,等全部的依賴安裝完畢
介紹下一些模塊的做用vue,vuex
爲vue項目使用的基本框架,express,vue-server-renderer,serialize-javascript
爲服務端渲染使用的模塊,babel-*
爲ES6轉換成ES5模塊,其餘的webpack*,*-loader
爲webpack構建所須要的模塊,若是須要項目學習webpack的使用,能夠閱讀官方文檔安裝階段完成了,下面進入愉快的編碼階段了,其實按照流程應該是編碼同時搞定打包、開發環境配置等工做的,爲了文章的效果,就分開說了
製做的頁面是一個沒有什麼業務情景的頁面(請原諒我,想到什麼就寫什麼代碼了),主要是爲了演示組件的引用流程,vuex狀態管理以及引用,狀態改變以後的視圖更新,異步操做的視圖更新,因此,當你下了源碼,大概頁面,你會看到下面這個奇奇怪怪的東西:
好了不要在乎這些細節了,咱們來看看這個怪怪的東西是怎麼出來的,先展現下項目最終的目錄結構:
其中
index.html
就是頁面最終生成頁的模板頁,裏面有簡單的頭部信息和佔位符,能夠在服務端渲染後進行內容替換app.js
就是頁面的邏輯入口文件,Vue對象在這裏實例化,其中使用的store,route能夠在實例化中傳入能夠看到
app.js
引用了App.vue
組件,.vue
是vue官方推出的單文件開發方式,配合webpack的vue-loader
能夠方便的實現模塊化開發,.vue
文件在打包的時候會被編譯成爲一個js對象,裏面包含一個render
方法,用於渲染頁面,下面是App.vue
文件
能夠看到頁面包含三個部分
template 、script 、style
,其中template爲組件使用的模板,如今vue2除了使用template,還可使用JSX和js模板,可是相對其餘兩種,template對於前端開發者來講仍是比較直觀的,script爲組件的邏輯部分,使用es6的進行模塊化,構建的時候會使用Vue.extend生成一個組件,style爲頁面的樣式部分,能夠指定lang
來聲明使用的樣式語法類型,能夠用原生的css,也能夠用stylus,sass等等,只要配置不一樣的webpack loader進行進行編譯就好了,另外能夠指定scoped
,使得組件中的樣式只對組件生效,不會影響其餘組件,不用擔憂命名重複的問題,其原理是在生成的時候爲標籤生成一段隨機數(沒研究過生成數的算法),而且爲選擇器加上對應隨機數的屬性選擇器。能夠看到組件
import
另一個List.vue
組件,而且在components
中進行了引用,template
中進行了引用,這就實現了組件的嵌套和複用,下面是List.vue
文件
這個文件使用了vuex管理的數據,在此前的版本的vuex中,在組件使用數據須要寫不少的
computed,methods
,在新版本的能夠配合ES6的展開函數和vuex的helper,簡寫不少函數,組件部份內容就說到這裏了,可能有人會說啥是computed,啥是methods,這些統統本身看文檔,
總的來講,寫一個組件須要瞭解下面幾點:
- 模板指令,例如
v-for,v-bind,v-on
等- 數據使用配置屬性
data,computed,props,watch
等- 組件的生命週期屬性
created,mounted
等- 全局方法
Vue.set,Vue.nextTick
等- 進階開發: 動畫效果,自定義指令,自定義插件,混合組件開發
下面說下用vuex作狀態管理,下面是
store/index.js
文件
能夠看到使用vuex須要在
Vue.use
中引入,而後實例化一個Vuex.Store
對象就能夠了,對象中須要定義state,actions,mutations,getters
等內容,這樣子就能夠創建一個全局的狀態管理機制,能夠從應用的頂端去處理數據,各個組件中對數據進行操做也是經過事件直接傳遞到Vuex中進行數據更新,而後再進行響應到其餘使用同個數據的組件中,進行視圖更新。項目的邏輯代碼已經完成了,可是對照上面ssr的概念,會發現還少了兩個webpack的
entry point
,一個是前端代碼的入口,能夠是供服務端渲染的入口,下面是前端client-entry.js
文件
文件引入了
app.js
,判斷若是在服務端渲染時已經寫入狀態,則將vuex的狀態進行替換,使得服務端渲染的html和vuex管理的數據是同步的。而後將vue實例掛載到html指定的節點中。下面是
server-entry.js
文件這裏面服務端會傳過來一個context對象,能夠從獲取信息,也能夠寫入信息,能夠看到將現有的vuex state賦值給context,給服務端渲染使用,最後返回vue對象(文檔中寫着須要返回一個Promise對象,對象中再返回一個vue對象,通過實驗直接返回也是能夠的,若是應用中存在異步操做會影響視圖和vuex數據狀態,那麼應該返回一個Promise對象,使得服務端獲得的vue對象是最後數據和視圖同步統一的)
代碼擼完了,下面要讓他跑起來了,配置分爲兩部分,一個是webpack打包的配置,一個是服務端渲染服務器的搭建,這裏使用express進行服務器的簡單搭建,不涉及任何負載均衡和性能優化問題,下面分別說說這兩個部分 :
- webpack打包:webpack打包主要有三個文件
webpack.base.config.js
,webpack.client.config.js
,webpack.server.cofnig.js
,其中base
主要配置了對應文件類型的loader,還有指定了entry的切割點,將業務代碼和庫,client
指定了client-entry.js
做爲entry point ,還將庫文件和業務文件進行分別打包,還有一些圖片處理,代碼壓縮的工做。server
指定了server-entry.js
做爲entry point,而且指定了打包了類型標準是commonjs2
,供服務端渲染模塊使用。- 而在開發過程當中,可使用
webpack-hot-middleware/client
,webpack-hot-middleware
去實現代碼的watch和從新構建雙端的代碼的流程,是得開發更加便捷,具體配置在setup-dev-server.js
中- 最後說一下服務端渲染的服務器配置,服務端部分使用
vue-server-renderer
模塊的createBundleRenderer
經過傳入剛纔webpack生成的server-bundler
去生成一個bundleRenderer
,就能夠調用renderToStream
或者renderToString
渲染頁面了,具體配置在server.js
中具體怎麼跑起項目能夠看下
package.json
的scripts屬性,其中dev
是開發用,start
是正式環境動態生成頁面用,build
能夠直接生成client-bundler
和server-bundler
基本上比較完整的vue2 前段端同構渲染已經介紹完了,下面說下我對框架的見解,前端框架這個東西基本上就是一時火一個,咱們在學習新東西的同時也應該不忘老本,要有本身的技術棧和工做流,就像《人月神話》中的一句話說的好,沒有解決任何事情的銀彈,對於不一樣的項目,不一樣的業務情景,應該採起不一樣的框架,使用最合適的開發架構去開發。
附上代碼 點我點我,給個star唄~
最後也沒啥好說的了,要不給你們拜個早年吧,祝你們代碼沒bug,哈哈