皮膚是什么
產(chǎn)品的ui 是前端按照設(shè)計(jì)師的設(shè)計(jì)稿,通過樣式組合一系列字體、圖片、視頻等資源,經(jīng)瀏覽器渲染引擎解析后渲染出的。
皮膚就是替換其中一部分的 樣式、字體、圖片、視頻等。
如何切換皮膚
切換皮膚就是切換樣式。
可能有同學(xué)會覺得只替換圖片、字體等資源不行么?是不行的,因?yàn)榇虬倪^程中有的資源是獨(dú)立的,有的是嵌入到了樣式中,沒法替換。

現(xiàn)在項(xiàng)目的css樣式是直接嵌入到頁面中的,通過在head里面生成各種style標(biāo)簽來內(nèi)嵌,這種情況下,如果想替換樣式的必須得覆蓋之前的,而樣式本身是有優(yōu)先級的,組件樣式使用了scoped的方式,優(yōu)先級較高,想覆蓋得通過!important來設(shè)置樣式優(yōu)先級。
這種方式太過hack,不是正確和優(yōu)雅的方式。更合理的方式是把樣式從頁面中分離出來,打包到單獨(dú)的css樣式文件中,然后直接替換css文件來實(shí)現(xiàn)切換皮膚效果。
皮膚樣式的管理
我們項(xiàng)目中的樣式是通過less管理的,可以定義一系列的變量,可以把皮膚涉及到的各種背景顏色,各種字體的大小等魔法值通過變量存儲,集中管理,類似這樣:
@loginBg: blue;
@loginBtnFontSize: 14px;
這個文件就是皮膚樣式的文件,比如秋天皮膚的配置文件可以叫autumn-skin-variables.less,在總配置variables.less中引用不同的皮膚less文件,使用不同的變量,來實(shí)現(xiàn)皮膚的切換。
動態(tài)換膚
應(yīng)用皮膚可以通過發(fā)版,靜態(tài)替換css。也可以動態(tài)的換膚,每次啟動請求服務(wù)端皮膚的接口,服務(wù)端會返回皮膚的版本號,和本地的皮膚版本做對比,若一致則忽略,如果不一致,則下載最新的樣式替換本地的,同時更新本地版本號。這就實(shí)現(xiàn)了動態(tài)的換膚。
甚至,可以做實(shí)時的換膚,服務(wù)端通過websocket推送過來最新的皮膚文件,然后程序自動應(yīng)用,就像投屏的技術(shù)方案一樣。
下載新的樣式文件需要消耗一些時間,這個過程可以在ui上展示一個進(jìn)度條或loading的圖片,提示用戶正在換膚。也可以不做任何提示,下載完成后自動應(yīng)用。
全量樣式包 vs 部分皮膚樣式包
上面說的是全量樣式包的方案,就是完整的替換css,這樣的方式簡單粗暴,但是下載樣式的過程長一些。
也可以只把皮膚相關(guān)的樣式單獨(dú)打包,來替換本地的皮膚樣式,這樣下載會快一些,但是寫代碼的時候要把皮膚相關(guān)樣式摘出來寫,類似下面這樣,否則還是會有優(yōu)先級問題,導(dǎo)致難以覆蓋。
.login{
background: @loginBg;
}
.login-btn{
font-size: @loginBtnFontSize;
}
全量包的方式 簡單,但是體積略大。
皮膚樣式單獨(dú)打包的方式 略復(fù)雜,但是體積小。
圖片、視頻等資源的處理
登錄頁有很多視頻,每個視頻的位置和寬高都不同,除了樣式的部分,視頻的dom元素也要動態(tài)生成。dom中的圖片等資源也是。
服務(wù)端的皮膚接口可以返回一個json,類似
{
version: '2.0.0',
loginVideos: [
{width:300,height:400, left: 400, top: 200, src:'http://xxx.com/xx.mp4'},
{width:300,height:400, left: 400, top: 200, src:'http://xxx.com/xx.mp4'},
],
css: "xxxxxxxx"
}
把版本號,視頻,樣式分開,客戶端通過一個SkinInstaller來替換css,生成視頻的dom元素,
原理圖如下:

皮膚相關(guān)規(guī)范
皮膚就是樣式和圖片、視頻、字體等的集合,可以修改的地方很多,但是為了快速開發(fā)和減少測試量,建議不要動位置、布局等,只替換相關(guān)的顏色、背景等資源和變量。
總結(jié)
動態(tài)換膚就是動態(tài)的切換css,可以是全部替換或者部分替換的方式,涉及到的dom元素需要動態(tài)生成。服務(wù)端可以返回一個描述皮膚的信息的json,客戶端通過解析json來做一系列的操作。
皮膚樣式基于less,把相關(guān)的變量集中到一個皮膚文件中管理,如果是部分替換的方式,還要把相關(guān)的樣式摘出來以單獨(dú)打包。