vue.js 開(kāi)發(fā)系列(三)Skeleton 骨架屏渲染

應(yīng)用場(chǎng)景

簡(jiǎn)單來(lái)說(shuō)病蛉,骨架屏(skeleton screen) 就是一個(gè)頁(yè)面從html 下載完成到 js 下載完成b并且執(zhí)行數(shù)據(jù)渲染這兩個(gè)時(shí)間點(diǎn)之間暫時(shí)渲染頁(yè)面基本結(jié)構(gòu)的方案挽唉。

而且這個(gè)骨架屏優(yōu)化鸭蛙,是有一定場(chǎng)景的,包括且不限于以下幾種情況:

  • 有懶加載機(jī)制的SPA路由
  • 多頁(yè)面程序的首頁(yè)渲染
  • SPA 中的非懶加載路由铃岔,但是數(shù)據(jù)量很大涉馁,完全load 并渲染數(shù)據(jù)需要花較長(zhǎng)時(shí)間
https://huangxuan.me/2017/07/12/upgrading-eleme-to-pwa

上圖形象地解釋了兩個(gè)多頁(yè)面程序之間的切換门岔,用Skeleton Screen 去優(yōu)化用戶(hù)觀(guān)感的方案。

Skeleton 渲染是在前端項(xiàng)目編譯時(shí)完成的谨胞,與之相對(duì)應(yīng)的是組件在瀏覽器runtime實(shí)時(shí)渲染成DOM固歪,從技術(shù)上講就是在服務(wù)器端預(yù)先把組件布局和數(shù)據(jù)渲染成html 字符串并且注入html 文件中。這需要服務(wù)器端渲染(ssr) 的支持胯努。如react 和 vue.js 這樣依賴(lài)虛擬DOM 的前端框架天然是支持服務(wù)器端渲染的。因?yàn)橹恍枰粋€(gè) JavaScript 在服務(wù)器端的執(zhí)行環(huán)境(例如V8 引擎)就可以輕易創(chuàng)建虛擬Dom并且映射為DOM tree逢防∫杜妫基于虛擬dom的服務(wù)器端渲染,最早起源于react忘朝,可以參考 strikingly 的技術(shù)博客

服務(wù)器端渲染

服務(wù)器端渲染作為skeleton screen的基本技術(shù)棧灰署,可以參考各前端框架的官方文檔钉赁,例如 vue-ssr guide. 主要是依賴(lài) vue-server-renderer 這個(gè)庫(kù)來(lái)實(shí)現(xiàn)

拿vue.js 組件來(lái)說(shuō)屿愚,在node.js 中渲染為 HTML 字符串可以簡(jiǎn)單分為幾步:

// 第 1 步:創(chuàng)建一個(gè) Vue 實(shí)例
const Vue = require('vue')
const app = new Vue({
// el: 是不需要的,因?yàn)橐坏┰O(shè)置目標(biāo) el孤钦,就會(huì)涉及document 操作
  template: `<div>Hello World</div>`
})

// 第 2 步:創(chuàng)建一個(gè) renderer
const renderer = require('vue-server-renderer').createRenderer()

// 第 3 步:將 Vue 實(shí)例渲染為 HTML
renderer.renderToString(app, (err, html) => {
  if (err) throw err
  console.log(html)
  // => <div data-server-rendered="true">Hello World</div>
})

上面的官方DEMO 很簡(jiǎn)單悦昵,直接在nodejs 腳本文件中定義vue 組件肴茄。但實(shí)際應(yīng)用中我們的組件一般都比較復(fù)雜,可能是一個(gè)入口 app.vue但指,依賴(lài)了好幾個(gè)組件寡痰,所以要用另外的方式去引入 new Vue 產(chǎn)生的 vm 對(duì)象. 這個(gè)vm 對(duì)象作為 renderer.renderToString 函數(shù)的第一個(gè)參數(shù)是最核心的。實(shí)際上通過(guò)跟蹤 vue-server-renderer 的源碼棋凳,ssr 還是依靠vue組件的render 函數(shù)來(lái)完成大部分工作 拦坠,render 函數(shù)是 vue 組件的核心函數(shù)。

                                          | installSSRHelpers(component); 
renderToString -> createRenderFunction -> | normalizeRender(component);  // get component render function
                                          | renderNode(component._render(), true, context); 
                                          // call component render to VNode.

幾個(gè)坑

  • document not defined

服務(wù)器端渲染并不等同于在服務(wù)器端啟動(dòng)一個(gè)瀏覽器進(jìn)程剩岳,所以無(wú)法獲取瀏覽器窗體中的window贞滨,document 等全局對(duì)象。一旦服務(wù)器端渲染的js 腳本中涉及到document 操作拍棕,就會(huì)報(bào)這個(gè) document not defined 的錯(cuò)誤晓铆。

所以要么就在vue 組件中或者所有依賴(lài)包中用到document 的地方都要做檢測(cè),要么就在服務(wù)器端渲染之前給global 對(duì)象加上document 定義 github issue

  • unexpected token =

在vue-server-renderer 的執(zhí)行過(guò)程中莫湘,提供了把vue 組件渲染成html 片段并且插入某個(gè) template HTML 中的API尤蒿, 在創(chuàng)建Renderer 的時(shí)候傳入一個(gè)template。后來(lái)發(fā)現(xiàn)ssr 的 template 中是不能包含類(lèi)似這種 <%= ddd > 符號(hào)的幅垮,也就是template 必須得符合vue 的template 語(yǔ)法腰池。

// 最后ssr 就會(huì)輸出 Vue 組件的內(nèi)容,并且注入到template 中 注釋 <!--vue-ssr-outlet--> 的地方

const renderer = createRenderer({
  template: require('fs').readFileSync('./index.template.html', 'utf-8')
})
const context = { title: 'Hello' }
renderer.renderToString(app, context, (err, html) => {
  // 頁(yè)面模板中 {{ title }} 將會(huì)是 "Hello"
})

具體參考 ssr 使用頁(yè)面模板
因?yàn)橛械暮蠖顺绦騿T習(xí)慣了 asp 或者 jsp 的template 語(yǔ)法,以 <%= 等作為數(shù)據(jù)插值表達(dá)式的開(kāi)頭示弓,會(huì)引起 vue ssr 的編譯失敗讳侨。

寫(xiě)在后面

綜上,這次我只是簡(jiǎn)單分析記錄了下 Skeleton 骨架屏實(shí)現(xiàn)的第一部分奏属,就是server side render跨跨,這是預(yù)先渲染的技術(shù)前提。實(shí)際上囱皿,這種后端拼接Html 字符串的活在php年代勇婴,python server中,甚至node.js server 中我們?cè)缇透蛇^(guò)了(ejs 或者 jade)嘱腥。本質(zhì)上都是拼接Html 字符串耕渴,提高SEO 和首屏響應(yīng)

在Github 上有許多基于服務(wù)器端渲染的靜態(tài)網(wǎng)站生成器或者 博客工具齿兔,可以實(shí)現(xiàn)比較好的瀏覽效果橱脸, 例如:vuepress.

關(guān)于骨架屏的實(shí)現(xiàn),業(yè)內(nèi)已經(jīng)有很成熟的方案分苇,既有基于 ssr 的添诉,也有直接基于瀏覽器內(nèi)核起個(gè)進(jìn)程預(yù)渲染的,完全不用vue 的ssr 技術(shù)棧医寿。下一次再具體分享下后者

參考閱讀:

vue ssr guide
餓了么升級(jí)PWA
vue.js 開(kāi)發(fā)系列二:render 函數(shù)
essential-guide-to-improve-seo-in-single-page-application-vuejs

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末栏赴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子糟红,更是在濱河造成了極大的恐慌艾帐,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盆偿,死亡現(xiàn)場(chǎng)離奇詭異柒爸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)事扭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)捎稚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人求橄,你說(shuō)我怎么就攤上這事今野。” “怎么了罐农?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵条霜,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我涵亏,道長(zhǎng)宰睡,這世上最難降的妖魔是什么蒲凶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮拆内,結(jié)果婚禮上旋圆,老公的妹妹穿的比我還像新娘。我一直安慰自己麸恍,他們只是感情好灵巧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著抹沪,像睡著了一般刻肄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上采够,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天肄方,我揣著相機(jī)與錄音,去河邊找鬼蹬癌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛虹茶,可吹牛的內(nèi)容都是我干的逝薪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蝴罪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼董济!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起要门,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤虏肾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后欢搜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體封豪,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年炒瘟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吹埠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疮装,死狀恐怖缘琅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情廓推,我是刑警寧澤刷袍,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站樊展,受9級(jí)特大地震影響呻纹,放射性物質(zhì)發(fā)生泄漏堆生。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一居暖、第九天 我趴在偏房一處隱蔽的房頂上張望顽频。 院中可真熱鬧,春花似錦太闺、人聲如沸糯景。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蟀淮。三九已至,卻和暖如春钞澳,著一層夾襖步出監(jiān)牢的瞬間怠惶,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工轧粟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留策治,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓兰吟,卻偏偏與公主長(zhǎng)得像通惫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子混蔼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 基于Vue的一些資料 內(nèi)容 UI組件 開(kāi)發(fā)框架 實(shí)用庫(kù) 服務(wù)端 輔助工具 應(yīng)用實(shí)例 Demo示例 element★...
    嘗了又嘗閱讀 1,151評(píng)論 0 1
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫(kù) m...
    你猜_3214閱讀 11,063評(píng)論 0 118
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫(kù) m...
    王喂馬_閱讀 6,454評(píng)論 1 77
  • UI組件 element - 餓了么出品的Vue2的web UI工具套件 Vux - 基于Vue和WeUI的組...
    魯大師666閱讀 43,392評(píng)論 5 97
  • 來(lái)源:http://www.cnblogs.com/opendigg/p/6513510.html UI組件 el...
    YU_XI閱讀 2,848評(píng)論 0 26