原生JS進(jìn)行前后端同構(gòu)
什么是前后端同構(gòu)
明確三個(gè)概念:「后端渲染」指?jìng)鹘y(tǒng)的 ASP、Java 或 PHP 的渲染機(jī)制;「前端渲染」指使用 JS 來(lái)渲染頁(yè)面大部分內(nèi)容,代表是現(xiàn)在流行的 SPA 單頁(yè)面應(yīng)用;「同構(gòu)渲染」指前后端共用 JS,首次渲染時(shí)使用 Node.js 來(lái)直出 HTML。一般來(lái)說(shuō)同構(gòu)渲染是介于前后端中的共有部分。
感覺(jué)前端的確是折騰,之前還在流行前后端分離,現(xiàn)在怎么又要做前后端同構(gòu)了?
原因是現(xiàn)在流行的SPA前端單頁(yè)面應(yīng)用比較沉重,首次訪問(wèn)需要加載文件較多,第一次加載過(guò)慢,用戶需要等待前端進(jìn)行渲染頁(yè)面。而且不利于SEO及緩存,并且有一定的開(kāi)發(fā)門(mén)檻。
前后端同構(gòu)通過(guò)復(fù)用模板和JS文件,讓一份代碼可以同時(shí)跑在服務(wù)器和瀏覽器,首次渲染使用nodejs渲染頁(yè)面,之后使用SPA路由跳轉(zhuǎn)。可以有效減少用戶首次訪問(wèn)的等待時(shí)間,并且對(duì)SEO比較友好,也便于緩存。
項(xiàng)目簡(jiǎn)介
本前后端同構(gòu)項(xiàng)目主要分為兩個(gè)部分,一個(gè)是基于koa2的渲染服務(wù)器,另一個(gè)是基于原生JS和zepto的前端SPA。
項(xiàng)目的特點(diǎn)是不使用vue和react等框架,門(mén)檻低,開(kāi)發(fā)速度快,便于上手,比較輕巧,核心的router部分只有一百行左右的代碼。適用于頁(yè)面交互較少,變化不頻繁的場(chǎng)景下,可以有效的提升性能和加載速度。
前端部分
前端部分的核心是路由部分,具體實(shí)現(xiàn)可以基于history API或是hash,網(wǎng)上有很多實(shí)現(xiàn),這次主要講下架構(gòu)
前端部分采用MVC分層結(jié)構(gòu)。
router層做的主要是創(chuàng)建路由示例,調(diào)用路由的get方法,給特定頁(yè)面綁定來(lái)自control層的函數(shù)。
形式如:
import control from '../control' //路由的構(gòu)造函數(shù)支持傳入渲染函數(shù),路由的全局名稱,路由跳轉(zhuǎn)前調(diào)用的鉤子 router = new Router(render,'ROUTER',beforeFn) router.get('/page/a', control.pageA')
control層主要做的是加載跟后端共有的渲染模板和渲染數(shù)據(jù),渲染出頁(yè)面后運(yùn)行頁(yè)面函數(shù)
形式如:
let control = { pageA(req,res) { //webpack的動(dòng)態(tài)加載,代碼分割功能 import(/* webpackChunkName: "pageA" */'script/pageA').then(module=> { // 檢測(cè)該頁(yè)面是否已有服務(wù)器渲染好,是的話直接運(yùn)行module.default //否則加載模板和數(shù)據(jù)進(jìn)行渲染,最后再調(diào)用頁(yè)面函數(shù) if(this.needRender(module.default)) { //加載數(shù)據(jù)時(shí)訪問(wèn)的地址就是當(dāng)前準(zhǔn)備渲染的頁(yè)面地址,只是加上了json=1的參數(shù) loadData('pageA').then(data => res.render(xtpl,data,module.default)) } } } // 捕捉webpack熱更新,讓他只進(jìn)行相當(dāng)于頁(yè)面跳轉(zhuǎn)的操作而不是刷新頁(yè)面 if(module.hot) { module.hot.accept(['script/pageA'], () => { control[ROUTER.req.currentControl].call(ROUTER,null,ROUTER.res) }) }
view層即模板,這里使用的是xtpl模板,在服務(wù)器環(huán)境和前端環(huán)境下都支持渲染頁(yè)面
頁(yè)面函數(shù)的形式
頁(yè)面函數(shù)要求使用es6的模塊寫(xiě)法,配合webpack的按需加載功能
export default () => { window.addEventListener('scroll', fn) //頁(yè)面函數(shù)支持返回一個(gè)卸載函數(shù),在頁(yè)面離開(kāi)的時(shí)候會(huì)被調(diào)用 //主要用于內(nèi)存的釋放,定時(shí)器的清除,事件監(jiān)聽(tīng)的移除等等 return function () { window.removeEventListener('scroll', fn) } }
后端部分
使用koa2搭建的一個(gè)渲染服務(wù)器,在收到前端傳來(lái)的頁(yè)面請(qǐng)求時(shí),會(huì)向API服務(wù)器請(qǐng)求數(shù)據(jù),并識(shí)別頁(yè)面請(qǐng)求是否帶有json=1的參數(shù),如果帶有,則為前端路由跳轉(zhuǎn)時(shí)的請(qǐng)求,直接返回?cái)?shù)據(jù)即可,如果沒(méi)有帶json參數(shù),加載跟前端共用的模板,配合數(shù)據(jù)進(jìn)行渲染,發(fā)送到瀏覽器。
相關(guān)文章
JavaScript中數(shù)組去除重復(fù)的三種方法
本文通過(guò)三種方法給大家介紹js數(shù)組去除重復(fù)的方法,實(shí)用性非常高,感興趣的朋友一起學(xué)習(xí)吧2016-04-04IE下通過(guò)a實(shí)現(xiàn)location.href 獲取referer的值
IE下采用window.location.href方式跳轉(zhuǎn)的話,referer值為空在標(biāo)簽a里面的跳轉(zhuǎn)的話referer就不會(huì)空,下面是具體的實(shí)現(xiàn)代碼2014-09-09微信小程序?qū)崿F(xiàn)驗(yàn)證碼倒計(jì)時(shí)效果
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)驗(yàn)證碼倒計(jì)時(shí)效果,手機(jī)登錄、填手機(jī)號(hào)獲取驗(yàn)證碼,倒計(jì)時(shí)后重新獲取效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05微信小程序?qū)崿F(xiàn)滑動(dòng)側(cè)邊欄
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)滑動(dòng)側(cè)邊欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07微信小程序動(dòng)態(tài)生成二維碼的實(shí)現(xiàn)代碼
這篇文章主要介紹了微信小程序動(dòng)態(tài)生成二維碼的實(shí)現(xiàn)代碼,需要的朋友可以參考下2018-07-07js中substring和substr的詳細(xì)介紹與用法
這篇文章介紹了js中substring和substr的用法,有需要的朋友可以參考一下2013-08-08