摘要:它會(huì)檢測出最大靜態(tài)子樹就是不需要?jiǎng)討B(tài)性的子樹并且從渲染函數(shù)中萃取出來。這樣在每次重渲染的時(shí)候,它就會(huì)直接重用完全相同的同時(shí)跳過比對(duì)。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。
新增:哈哈,最近又推出了 vue 的文章,在這里放個(gè)鏈接~
手把手教你從零寫一個(gè)簡單的 VUE
感謝有人看我扯技術(shù),這篇文章主要介紹最近非常火的vue2前端框架的特點(diǎn)和vue2+vuex2+webpack2各種2的前后端同構(gòu)渲染架構(gòu)搭建流程,最后會(huì)附上代碼,文章想到啥寫啥,如果存在錯(cuò)誤,或者大家有什么意見建議,歡迎大家指出來
Vue2 和 Vue1 的對(duì)比vue2出來之后,基本上逛論壇逛技術(shù)群都能看到各種文章,各種討論 ,一時(shí)間大家都在學(xué)習(xí)vue2了 ,我今年年初就開始接觸vue,最初也是在react ,angular,vue 之中對(duì)比選擇,最終選擇了vue,因?yàn)槠鋵?duì)前端比較友好(使用正常的模板,而不是JSX)、概念及學(xué)習(xí)成本相對(duì)簡單(對(duì)于團(tuán)隊(duì)開發(fā),引入技術(shù)必須要考慮其學(xué)習(xí)成本),下面介紹下我理解的vue2和vue1的不同之處 ,如有不足,歡迎補(bǔ)充:
1.引入了virtual Dom
在vue1中,數(shù)據(jù)和視圖的綁定流程是通過 Object.defineProperty將數(shù)據(jù)轉(zhuǎn)化為getter/setter,getter/setter中加入watcher,當(dāng)對(duì)數(shù)據(jù)進(jìn)行操作的時(shí)候,setter的watch被觸發(fā)重新計(jì)算,然后更新和這個(gè)數(shù)據(jù)有關(guān)聯(lián)的dom元素,這就是vue1的數(shù)據(jù)驅(qū)動(dòng)視圖原理
在vue2中,數(shù)據(jù)的綁定和觸發(fā)和vue1相同,基本原理都是通過Object.defineProperty對(duì)數(shù)據(jù)加入"鉤子",以便在數(shù)據(jù)發(fā)生變化的時(shí)候得以響應(yīng),而在響應(yīng)之后,不像vue1一樣直接更新dom元素,而是放入virtual Dom中,進(jìn)行比對(duì)計(jì)算,然后對(duì)dom元素做相應(yīng)的處理。下面是vue1和vue2的響應(yīng)流程對(duì)比vue:
vue2:
關(guān)于virtual Dom: 虛擬dom最初是在react上面認(rèn)識(shí)的,其實(shí)做的事情就是在js內(nèi)存中建立好dom的結(jié)構(gòu),然后再更新虛擬dom時(shí)做差異比對(duì),將差異的地方真正更新到頁面中,做到最小化頁面的渲染。當(dāng)然,也不是說對(duì)于所有情景,虛擬dom的性能都是最好的,畢竟比起直接操作dom元素,他還是需要在內(nèi)存中進(jìn)行計(jì)算,因此對(duì)于少量的元素更新,可能其性能比起直接操作dom元素要差。當(dāng)然虛擬dom的引入,不只是在性能方面的考慮,虛擬dom可以帶來編程的變化,比如你可以使用render方法直接創(chuàng)建新的節(jié)點(diǎn),虛擬dom也是vue2可以進(jìn)行服務(wù)端渲染的關(guān)鍵,由于虛擬dom是在內(nèi)存重點(diǎn),vue2的ssr可以將虛擬dom直接生成html的字符串,從而實(shí)現(xiàn)ssr。除此之外,vue2 從模板到 virtuel-DOM 的編譯階段使用了一些高階優(yōu)化:
(1). 它會(huì)檢測出靜態(tài)的 class 名和 attributes 這樣它們?cè)诔跏蓟秩局缶陀肋h(yuǎn)都不會(huì)再被比對(duì)。
(2). 它會(huì)檢測出最大靜態(tài)子樹 (就是不需要?jiǎng)討B(tài)性的子樹) 并且從渲染函數(shù)中萃取出來。這樣在每次重渲染的時(shí)候,它就會(huì)直接重用完全相同的 virtual nodes 同時(shí)跳過比對(duì)。
這些高階優(yōu)化通常只會(huì)在使用 JSX 時(shí)通過 Babel plugin 來做,但是 vue2 即使在使用瀏覽器內(nèi)的編譯器時(shí)也能做到。
2.組件事件傳遞機(jī)制的改變,組件數(shù)據(jù)雙向綁定的去除
vue2組件廢除了$dispath/$broadcast父子組件的事件傳播方式,廢除了過濾器,props參數(shù)等的數(shù)據(jù)雙向綁定以及處理功能,說明作者希望使用者通過建立全局的狀態(tài)管理,事件管理機(jī)制,通過使用事件中心,允許組件自由交流,無論組件處于組件樹的哪一層,將狀態(tài)管理集中在一起處理,官方提供的vuex就是用來幾種管理狀態(tài)的。
3.服務(wù)端渲染 ssr:server-side-render
由于virtual dom的引入,使得vue的服務(wù)端渲染成為了可能,下面是官方 vue-server-renderer提供的渲染流程圖:
可以看出vue的server-side-render有三部分組成,一部分是頁面的源碼(source),還有node層的渲染部分和瀏覽器端的渲染部分。
source分為兩種entry point,一個(gè)是前端頁面的入口client entry,主要是實(shí)例化Vue對(duì)象,將其掛載到頁面中;另外一個(gè)是后端渲染服務(wù)入口server entry,主要是控服務(wù)端渲染模塊回調(diào),返回一個(gè)Promise對(duì)象,最終返回一個(gè)Vue對(duì)象(經(jīng)過測試,直接返回Vue對(duì)象也是可以的);
前面的source部分就是業(yè)務(wù)開發(fā)的代碼,開發(fā)完成之后通過 webpack 進(jìn)行構(gòu)建,生成對(duì)應(yīng)的bundle,這里不再贅述client bundle,就是一個(gè)可在瀏覽器端執(zhí)行的打包文件;這里說下server bundle, vue2提供 vue-server-renderer模塊,模塊可以提供兩種render: rendererer/bundleRenderer ,下面分別介紹下這兩種render。
renderer接收一個(gè)vue對(duì)象 ,然后進(jìn)行渲染,這種對(duì)于簡單的vue對(duì)象,可以這么去做,但是對(duì)于復(fù)雜的項(xiàng)目,如果使用這種直接require一個(gè)vue對(duì)象,這個(gè)對(duì)于服務(wù)端代碼的結(jié)構(gòu)和邏輯都不太友好,首先模塊的狀態(tài)會(huì)一直延續(xù)在每個(gè)請(qǐng)求渲染請(qǐng)求,我們需要去管理和避免這次渲染請(qǐng)求的狀態(tài)影響到后面的請(qǐng)求,因此vue-server-renderer提供了另外一種渲染模式,通過一個(gè) bundleRenderer去做渲染。
bundleRenderer是較為復(fù)雜項(xiàng)目進(jìn)行服務(wù)端渲染官方推薦的方式,通過webpack以server entry按照一定的要求打包生成一個(gè) server-bundle,它相當(dāng)于一個(gè)可以給服務(wù)端用的app的打包壓縮文件,每一次調(diào)用都會(huì)重新初始化 vue對(duì)象,保證了每次請(qǐng)求都是獨(dú)立的,對(duì)于開發(fā)者來說,只需要專注于當(dāng)前業(yè)務(wù)就可以,不用為服務(wù)端渲染開發(fā)更多的邏輯代碼。
renderer生成完成之后,都存在兩個(gè)接口,分別是renderToString和renderToStream,一個(gè)是一次性將頁面渲染成字符串文件,另外一個(gè)是流式渲染,適用于支持流的web服務(wù)器,可以是請(qǐng)求服務(wù)的速度更快
4.除了上面說的那些不同,vue2在生命周期管理,動(dòng)畫機(jī)制等地方都與vue有些差別,具體請(qǐng)瀏覽migration
Vuex2 和 Vuex 、Webpack2 和 Webpack 的不同之處 vuexwebpack相對(duì)于 vue2和vue 較大改動(dòng),vue的狀態(tài)管理工具 vuex的改動(dòng)不是很大,底層改動(dòng)由于時(shí)間關(guān)系還沒有來得及細(xì)究,但是在使用方面多了幾個(gè) Helper,利用ES6的展開函數(shù)可以更加方便的使用state,getters,mutations,actions。下面簡單介紹下vuex各個(gè)部分的概念
state是一個(gè)全局的狀態(tài)存儲(chǔ),數(shù)據(jù)會(huì)存儲(chǔ)在其中,vue組件可以直接訪問其中的值,但是只可以讀,不可以進(jìn)行寫操作
getter,有些時(shí)候我們需要對(duì)獲取的數(shù)據(jù)進(jìn)行加工,而不是直接獲取state中的數(shù)據(jù),這時(shí)候可以通過getter定義函數(shù),返回對(duì)應(yīng)的數(shù)據(jù)
mutations是vuex中唯一一個(gè)可以修改數(shù)據(jù)的地方,mutations可以定義事件函數(shù),在vue組件中可以通過commit發(fā)射事件,調(diào)用函數(shù)。需要注意的是,mutations中的操作必須是同步的,不可以存在異步操作的情況。
actions和 mutation比較相似,不同的是actions中不直接修改state,而是通過commit調(diào)用mutations修改數(shù)據(jù),而且actions中可以存在異步處理邏輯
從零開始搭項(xiàng)目webpack2 和 webpack對(duì)比,有以下的新特性:
ES6 Modules : webpack 2 已經(jīng)支持原生的 ES6 的模塊加載器了,這意味著 webpack 2 能夠理解和處理 import和export了,而不用把他們轉(zhuǎn)化成 CommonJS 來處理了。
用 ES6 來做代碼拆分 : ES6 的模塊加載器定義了System.import這一個(gè)方法,System.import能夠在運(yùn)行時(shí)動(dòng)態(tài)加載 ES6 模塊。
混合使用 ES6 和 AMD 和 CommonJS (Mixing ES6 with AMD and CommonJS)
更加具體的新特性可以瀏覽鏈接地址
好了,前面扯了那么多東西,估計(jì)沒什么人看,我們還是回歸題目,開始敲代碼吧,哈哈,接下來我會(huì)使用vue2 + vuex2 + webpack2 搭建一個(gè)簡單的 ssr項(xiàng)目,能夠直出頁面,還能夠保存成靜態(tài)文件。雖然官方頁面響應(yīng)的實(shí)例vue-hackernews-2.0,但是如果一開始把代碼下下來,還是不太容易理解的,所以我參考其例子,從零開始搭建項(xiàng)目,源碼在文章的最后
首先當(dāng)然是使用npm init新建一個(gè)項(xiàng)目
然后往package.json中寫入下列依賴然后運(yùn)行 npm i ,然后去上個(gè)廁所,喝杯茶也行,等所有的依賴安裝完畢
介紹下一些模塊的作用 vue,vuex 為vue項(xiàng)目使用的基本框架,express,vue-server-renderer,serialize-javascript為服務(wù)端渲染使用的模塊,babel-*為ES6轉(zhuǎn)換成ES5模塊,其他的webpack*,*-loader為webpack構(gòu)建所需要的模塊,如果需要項(xiàng)目學(xué)習(xí)webpack的使用,可以閱讀官方文檔安裝階段完成了,下面進(jìn)入愉快的編碼階段了,其實(shí)按照流程應(yīng)該是編碼同時(shí)搞定打包、開發(fā)環(huán)境配置等工作的,為了文章的效果,就分開說了
制作的頁面是一個(gè)沒有什么業(yè)務(wù)情景的頁面(請(qǐng)?jiān)徫?,想到什么就寫什么代碼了),主要是為了演示組件的引用流程,vuex狀態(tài)管理以及引用,狀態(tài)改變之后的視圖更新,異步操作的視圖更新,所以,當(dāng)你下了源碼,大概頁面,你會(huì)看到下面這個(gè)奇奇怪怪的東西:
好了不要在意這些細(xì)節(jié)了,我們來看看這個(gè)怪怪的東西是怎么出來的,先展示下項(xiàng)目最終的目錄結(jié)構(gòu):
其中index.html就是頁面最終生成頁的模板頁,里面有簡單的頭部信息和占位符,可以在服務(wù)端渲染后進(jìn)行內(nèi)容替換
app.js就是頁面的邏輯入口文件,Vue對(duì)象在這里實(shí)例化,其中使用的store,route可以在實(shí)例化中傳入可以看到app.js引用了App.vue組件,.vue是vue官方推出的單文件開發(fā)方式,配合webpack的vue-loader可以方便的實(shí)現(xiàn)模塊化開發(fā),.vue文件在打包的時(shí)候會(huì)被編譯成為一個(gè)js對(duì)象,里面包含一個(gè)render方法,用于渲染頁面,下面是App.vue文件
可以看到頁面包含三個(gè)部分template 、script 、style,其中template為組件使用的模板,現(xiàn)在vue2除了使用template,還可以使用JSX和js模板,但是相對(duì)其他兩種,template對(duì)于前端開發(fā)者來說還是比較直觀的,script為組件的邏輯部分,使用es6的進(jìn)行模塊化,構(gòu)建的時(shí)候會(huì)使用Vue.extend生成一個(gè)組件,style為頁面的樣式部分,可以指定lang來聲明使用的樣式語法類型,可以用原生的css,也可以用stylus,sass等等,只要配置不同的webpack loader進(jìn)行進(jìn)行編譯就行了,另外可以指定 scoped,使得組件中的樣式只對(duì)組件生效,不會(huì)影響其他組件,不用擔(dān)心命名重復(fù)的問題,其原理是在生成的時(shí)候?yàn)闃?biāo)簽生成一段隨機(jī)數(shù)(沒研究過生成數(shù)的算法),并且為選擇器加上對(duì)應(yīng)隨機(jī)數(shù)的屬性選擇器。
可以看到組件import另外一個(gè)List.vue組件,并且在components中進(jìn)行了引用,template中進(jìn)行了引用,這就實(shí)現(xiàn)了組件的嵌套和復(fù)用,下面是List.vue文件
這個(gè)文件使用了vuex管理的數(shù)據(jù),在此前的版本的vuex中,在組件使用數(shù)據(jù)需要寫很多的computed,methods,在新版本的可以配合ES6的展開函數(shù)和vuex的helper,簡寫很多函數(shù),組件部分內(nèi)容就說到這里了,可能有人會(huì)說啥是computed,啥是methods,這些通通自己看文檔,
總的來說,寫一個(gè)組件需要了解下面幾點(diǎn):模板指令,例如v-for,v-bind,v-on等
數(shù)據(jù)使用配置屬性data,computed,props,watch等
組件的生命周期屬性created,mounted等
全局方法Vue.set,Vue.nextTick等
進(jìn)階開發(fā): 動(dòng)畫效果,自定義指令,自定義插件,混合組件開發(fā)
下面說下用vuex做狀態(tài)管理,下面是store/index.js文件
可以看到使用vuex需要在Vue.use中引入,然后實(shí)例化一個(gè)Vuex.Store對(duì)象就可以了,對(duì)象中需要定義state,actions,mutations,getters等內(nèi)容,這樣子就可以建立一個(gè)全局的狀態(tài)管理機(jī)制,可以從應(yīng)用的頂端去處理數(shù)據(jù),各個(gè)組件中對(duì)數(shù)據(jù)進(jìn)行操作也是通過事件直接傳遞到Vuex中進(jìn)行數(shù)據(jù)更新,然后再進(jìn)行響應(yīng)到其他使用同個(gè)數(shù)據(jù)的組件中,進(jìn)行視圖更新。
項(xiàng)目的邏輯代碼已經(jīng)完成了,但是對(duì)照上面ssr的概念,會(huì)發(fā)現(xiàn)還少了兩個(gè)webpack的entry point,一個(gè)是前端代碼的入口,可以是供服務(wù)端渲染的入口,下面是前端client-entry.js文件
文件引入了app.js,判斷如果在服務(wù)端渲染時(shí)已經(jīng)寫入狀態(tài),則將vuex的狀態(tài)進(jìn)行替換,使得服務(wù)端渲染的html和vuex管理的數(shù)據(jù)是同步的。然后將vue實(shí)例掛載到html指定的節(jié)點(diǎn)中。
下面是server-entry.js文件
這里面服務(wù)端會(huì)傳過來一個(gè)context對(duì)象,可以從獲取信息,也可以寫入信息,可以看到將現(xiàn)有的vuex state賦值給context,給服務(wù)端渲染使用,最后返回vue對(duì)象(文檔中寫著需要返回一個(gè)Promise對(duì)象,對(duì)象中再返回一個(gè)vue對(duì)象,經(jīng)過實(shí)驗(yàn)直接返回也是可以的,如果應(yīng)用中存在異步操作會(huì)影響視圖和vuex數(shù)據(jù)狀態(tài),那么應(yīng)該返回一個(gè)Promise對(duì)象,使得服務(wù)端得到的vue對(duì)象是最后數(shù)據(jù)和視圖同步統(tǒng)一的)
代碼擼完了,下面要讓他跑起來了,配置分為兩部分,一個(gè)是webpack打包的配置,一個(gè)是服務(wù)端渲染服務(wù)器的搭建,這里使用express進(jìn)行服務(wù)器的簡單搭建,不涉及任何負(fù)載均衡和性能優(yōu)化問題,下面分別說說這兩個(gè)部分 :
webpack打包:webpack打包主要有三個(gè)文件webpack.base.config.js,webpack.client.config.js,webpack.server.cofnig.js,其中base主要配置了對(duì)應(yīng)文件類型的loader,還有指定了entry的切割點(diǎn),將業(yè)務(wù)代碼和庫,client指定了client-entry.js作為entry point ,還將庫文件和業(yè)務(wù)文件進(jìn)行分別打包,還有一些圖片處理,代碼壓縮的工作。server指定了server-entry.js作為entry point,并且指定了打包了類型標(biāo)準(zhǔn)是commonjs2,供服務(wù)端渲染模塊使用。
而在開發(fā)過程中,可以使用webpack-hot-middleware/client,webpack-hot-middleware去實(shí)現(xiàn)代碼的watch和重新構(gòu)建雙端的代碼的流程,是得開發(fā)更加便捷,具體配置在setup-dev-server.js中
最后說一下服務(wù)端渲染的服務(wù)器配置,服務(wù)端部分使用vue-server-renderer模塊的createBundleRenderer通過傳入剛才webpack生成的server-bundler去生成一個(gè)bundleRenderer,就可以調(diào)用renderToStream或者renderToString渲染頁面了,具體配置在server.js中
具體怎么跑起項(xiàng)目可以看下package.json的scripts屬性,其中dev是開發(fā)用,start是正式環(huán)境動(dòng)態(tài)生成頁面用,build可以直接生成client-bundler和server-bundler
基本上比較完整的vue2 前段端同構(gòu)渲染已經(jīng)介紹完了,下面說下我對(duì)框架的看法,前端框架這個(gè)東西基本上就是一時(shí)火一個(gè),我們?cè)趯W(xué)習(xí)新東西的同時(shí)也應(yīng)該不忘老本,要有自己的技術(shù)棧和工作流,就像《人月神話》中的一句話說的好,沒有解決任何事情的銀彈,對(duì)于不同的項(xiàng)目,不同的業(yè)務(wù)情景,應(yīng)該采取不同的框架,使用最合適的開發(fā)架構(gòu)去開發(fā)。
附上代碼 點(diǎn)我點(diǎn)我,給個(gè)star唄~
最后也沒啥好說的了,要不給大家拜個(gè)早年吧,祝大家代碼沒bug,哈哈
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/91030.html
摘要:它會(huì)檢測出最大靜態(tài)子樹就是不需要?jiǎng)討B(tài)性的子樹并且從渲染函數(shù)中萃取出來。這樣在每次重渲染的時(shí)候,它就會(huì)直接重用完全相同的同時(shí)跳過比對(duì)。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。 新增:哈哈,最近又推出了 vue 的文章,在這里放個(gè)鏈接~手把手教你從零寫一個(gè)簡單的 VUE 感謝有人看我扯技術(shù),這篇文章主要介紹最近非?;鸬膙ue2前端框架的特點(diǎn)和vue2+vuex2+we...
摘要:它會(huì)檢測出最大靜態(tài)子樹就是不需要?jiǎng)討B(tài)性的子樹并且從渲染函數(shù)中萃取出來。這樣在每次重渲染的時(shí)候,它就會(huì)直接重用完全相同的同時(shí)跳過比對(duì)。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。 新增:哈哈,最近又推出了 vue 的文章,在這里放個(gè)鏈接~手把手教你從零寫一個(gè)簡單的 VUE 感謝有人看我扯技術(shù),這篇文章主要介紹最近非?;鸬膙ue2前端框架的特點(diǎn)和vue2+vuex2+we...
摘要:無需使用服務(wù)器實(shí)時(shí)動(dòng)態(tài)編譯,而是使用預(yù)渲染方式,在構(gòu)建時(shí)簡單地生成針對(duì)特定路由的靜態(tài)文件。與可以部署在任何靜態(tài)文件服務(wù)器上的完全靜態(tài)單頁面應(yīng)用程序不同,服務(wù)器渲染應(yīng)用程序,需要處于運(yùn)行環(huán)境。更多的服務(wù)器端負(fù)載。 目錄結(jié)構(gòu) -no-ssr-demo 未做ssr之前的項(xiàng)目代碼用于對(duì)比 -vuecli2ssr 將vuecli生成的項(xiàng)目轉(zhuǎn)為ssr -prerender-demo 使用prer...
摘要:本文源碼簡介之前剛?cè)腴T并做好了一個(gè)簡而全的純?nèi)彝暗捻?xiàng)目,數(shù)據(jù)都是本地模擬請(qǐng)求的詳情請(qǐng)移步這里為了真正做到數(shù)據(jù)庫的真實(shí)存取,于是又開始入門了并以此來為之前的頁面寫后臺(tái)數(shù)據(jù)接口。 本文源碼:Github 簡介: 之前剛?cè)腴Tvue并做好了一個(gè)簡而全的純vue2全家桶的項(xiàng)目,數(shù)據(jù)都是本地 json 模擬請(qǐng)求的;詳情請(qǐng)移步這里:vue-proj-demo 為了真正做到數(shù)據(jù)庫的真實(shí)存取,于是又...
閱讀 3033·2023-04-25 21:23
閱讀 3112·2021-09-22 15:24
閱讀 888·2019-08-30 12:55
閱讀 2125·2019-08-29 18:42
閱讀 2634·2019-08-29 16:27
閱讀 977·2019-08-26 17:40
閱讀 2231·2019-08-26 13:29
閱讀 2636·2019-08-26 11:45