搜索發(fā)現(xiàn)有下面兩個(gè)骨架屏插件(方案)
- page-skeleton-webpack-plugin
- vue-skeleton-webpack-plugin
page-skeleton-webpack-plugin
page-skeleton-webpack-plugin是餓了么團(tuán)隊(duì)開發(fā)的,但目前好像已經(jīng)停止維護(hù)了,所以入坑需謹(jǐn)慎。這個(gè)插件的優(yōu)點(diǎn)是可以自動(dòng)生成骨架屏。但是它不支持hash路由,不適用項(xiàng)目,所以采用下面的方案。關(guān)于這個(gè)插件的使用可以看官方文檔,或者參考一下這篇文章
vue-skeleton-webpack-plugin
vue-skeleton-webpack-plugin項(xiàng)目上提供了很多示例,但實(shí)際用起來卻有很多問題。而且這個(gè)插件需要自己實(shí)現(xiàn)骨架屏頁(yè)面。根據(jù)項(xiàng)目里的示例(vue-cli3)進(jìn)行配置。根據(jù)issue對(duì)不同頁(yè)面顯示不同骨架屏進(jìn)行了處理。
配置
// skeleton.js
import Vue from 'vue'
import listSkeleton from './skeleton/listSkeleton'
import detailSkeleton from './skeleton/detailSkeleton'
export default new Vue({
components: {
listSkeleton,
detailSkeleton
},
template: `
<div>
<listSkeleton id="listSkeleton" style="display:none;" />
<detailSkeleton id="detailSkeleton" style="display:none;" />
</div>
`
});
// vue.config.js
configureWebpack: {
plugins: [
// 骨架屏配置
new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
index: path.join(__dirname, './src/skeleton.js'),
},
},
minimize: true,
quiet: true,
router: {
mode: 'hash',
routes: [
{ path: '/', skeletonId: 'listSkeleton' },
{ path: /^\/detail/, skeletonId: 'detailSkeleton' }
]
}
}),
],
},
// 在開發(fā)模式下分離css樣式,讓骨架屏的css在開發(fā)模式下生效
css: {
extract: true
}
其他配置項(xiàng)可以看文檔,這里我踩的幾個(gè)坑:
- entry入口的名字,示例里寫的是app,但我的項(xiàng)目里是index
- 示例中將main.js做了這樣的處理,目的是在css文件加載完成時(shí)再掛載Vue,以解決我下面說的白屏問題。具體可以參考項(xiàng)目的issue#62。但是可能是因?yàn)轫?xiàng)目配置的緣故,找不到
window.STYLE_READY,導(dǎo)致骨架屏不消失,最后沒改動(dòng)main.js。
// main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
const app = new Vue({
components: {
App,
},
render: h => h(App),
});
window.mountApp = () => {
app.$mount('#app');
};
if (process.env.NODE_ENV === 'production') {
if (window.STYLE_READY) {
window.mountApp();
}
} else {
window.mountApp();
}
- 最后是在開發(fā)環(huán)境css無效的問題,issue中也有提到,需要在開發(fā)環(huán)境抽離css。下次讓設(shè)計(jì)師小哥給張骨架屏的圖好了,就不用寫css了。
上述兩個(gè)插件的原理都是一樣的。假設(shè)Vue掛載的元素是<div id="app"></div>,如果我們?cè)谶@個(gè)元素寫一些內(nèi)容,vue未加載完成時(shí)就會(huì)顯示在頁(yè)面中;當(dāng)vue掛載時(shí),會(huì)刪除<div id="app"></div>內(nèi)的內(nèi)容。我們可以通過這個(gè)原理實(shí)現(xiàn)Vue框架的骨架屏。
但是個(gè)人認(rèn)為這個(gè)方案其實(shí)有些問題:
- 無法控制骨架屏消失的時(shí)機(jī),如果我希望在首屏加載數(shù)據(jù)時(shí)顯示骨架屏,加載完后消失,基于這樣的原理很難實(shí)現(xiàn)
- 在Vue掛載到頁(yè)面顯示內(nèi)容還有一定的白屏?xí)r間
- 無法實(shí)現(xiàn)局部骨架屏,在頁(yè)面上顯示局部骨架屏代替loading效果
即使這樣,這個(gè)方案其實(shí)已經(jīng)使用大多數(shù)情況了。對(duì)于SPA來說,一般只有首頁(yè)加載較久,切換“頁(yè)面”時(shí)幾乎不需要等待時(shí)間,所以我們只需要在首屏加載骨架屏。但我們不知道用戶第一次進(jìn)入的是哪個(gè)頁(yè)面,所以我們需要根據(jù)路由判斷當(dāng)前頁(yè)面,加載不同的骨架屏。
不能自動(dòng)生成骨架屏是個(gè)硬傷,如果頁(yè)面更新,也要去維護(hù)骨架屏。讓設(shè)計(jì)師小哥切個(gè)圖是個(gè)不錯(cuò)的方法,但我們還是要追求自動(dòng)化。
以后的優(yōu)化目標(biāo)應(yīng)該是
- 自動(dòng)化生成骨架屏
- 骨架屏動(dòng)畫
- 可以控制骨架屏消失的時(shí)機(jī)
- 局部骨架屏,代替loading效果
參考文章:
Vue頁(yè)面骨架屏注入實(shí)踐
為vue項(xiàng)目添加骨架屏
餓了么的 PWA 升級(jí)實(shí)踐