vue-cli3配置骨架屏方案
前言
最近在學vue
,準備使用vue寫一個移動端項目。考慮到首頁白屏優化,需要實現骨架屏需求。這裏介紹兩種方案,當然都是根據現有的輪子搭的
步驟
- 安裝
vue-skeleton-webpack-plugin
插件
npm install --save-dev vue-skeleton-webpack-plugin
- vue.config.js配置
const path = require('path')
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin');
module.exports = {
css: {
extract: true, // css拆分ExtractTextPlugin插件,默認true - 骨架屏需要爲true
},
configureWebpack: (config)=>{
// vue骨架屏插件配置
config.plugins.push(new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, './src/utils/skeleton.js'),
},
},
minimize: true,
quiet: true,
}))
},
}
- 新建一個
skeleton.js
文件放在src->utils
文件夾下面、
import Vue from 'vue';
import Skeleton from '../components/Skeleton/skeleton-2';
export default new Vue({
components: {
Skeleton,
},
render: h => h(Skeleton),
});
這個文件是用來注入骨架屏的
- 新建一個
skeleton-2.vue
骨架屏組件
<template>
<div class="skeleton page">
<div class="skeleton-nav"></div>
<div class="skeleton-swiper"></div>
<ul class="skeleton-tabs">
<li v-for="i in 8" class="skeleton-tabs-item"><span></span></li>
</ul>
<div class="skeleton-banner"></div>
<div v-for="i in 6" class="skeleton-productions"></div>
</div>
</template>
<style>
.skeleton {
position: relative;
height: 100%;
overflow: hidden;
padding: 15px;
box-sizing: border-box;
background: #fff;
}
.skeleton-nav {
height: 45px;
background: #eee;
margin-bottom: 15px;
}
.skeleton-swiper {
height: 160px;
background: #eee;
margin-bottom: 15px;
}
.skeleton-tabs {
list-style: none;
padding: 0;
margin: 0 -15px;
display: flex;
flex-wrap: wrap;
}
.skeleton-tabs-item {
width: 25%;
height: 55px;
box-sizing: border-box;
text-align: center;
margin-bottom: 15px;
}
.skeleton-tabs-item span {
display: inline-block;
width: 55px;
height: 55px;
border-radius: 55px;
background: #eee;
}
.skeleton-banner {
height: 60px;
background: #eee;
margin-bottom: 15px;
}
.skeleton-productions {
height: 20px;
margin-bottom: 15px;
background: #eee;
}
.skeleton {
padding: 10px;
}
.skeleton .skeleton-head,
.skeleton .skeleton-title,
.skeleton .skeleton-content {
background: rgb(194, 207, 214);
}
.skeleton-head {
width: 100px;
height: 100px;
float: left;
}
.skeleton-body {
margin-left: 110px;
}
.skeleton-title {
width: 500px;
height: 60px;
transform-origin: left;
animation: skeleton-stretch .5s linear infinite alternate;
}
.skeleton-content {
width: 260px;
height: 30px;
margin-top: 10px;
transform-origin: left;
animation: skeleton-stretch .5s -.3s linear infinite alternate;
}
@keyframes skeleton-stretch {
from {
transform: scalex(1);
}
to {
transform: scalex(.3);
}
}
</style>
- 新建一個
skeleton-1.vue
骨架屏組件
<template>
<div class="skeleton">
<div class="skeleton-head"></div>
<div class="skeleton-body">
<div class="skeleton-title"></div>
<div class="skeleton-content"></div>
</div>
</div>
</template>
<style>
.skeleton {
padding: 10px;
}
.skeleton .skeleton-head,
.skeleton .skeleton-title,
.skeleton .skeleton-content {
background: rgb(194, 207, 214);
}
.skeleton-head {
width: 100px;
height: 100px;
float: left;
}
.skeleton-body {
margin-left: 110px;
}
.skeleton-title {
width: 500px;
height: 60px;
transform-origin: left;
animation: skeleton-stretch 0.5s linear infinite alternate;
}
.skeleton-content {
width: 260px;
height: 30px;
margin-top: 10px;
transform-origin: left;
animation: skeleton-stretch 0.5s -0.3s linear infinite alternate;
}
@keyframes skeleton-stretch {
from {
transform: scalex(1);
}
to {
transform: scalex(0.3);
}
}
</style>
- 修改
main.js配置
const app = new Vue({
store,
router,
render: h => h(App)
}).$mount('#app')
- 重啓項目
思路
- 將骨架屏也看成路由組件,在構建時使用 Vue 預渲染功能,將骨架屏組件的渲染結果 HTML 片段插入 HTML 頁面模版的掛載點中,將樣式內聯到 head 標籤中。這樣等前端渲染完成時,Vue 將使用客戶端混合,把掛載點中的骨架屏內容替換成真正的頁面內容。
缺點
- 這種方案實現的是固定死的骨架(可以查看
skeleton-2.vue
skeleton-1.vue
)兩個文件,不能夠自動根據頁面DOM結構生成骨架
優化的方向 (這裏補充第二種方案)
餓了麼團隊 page-skeleton-webpack-plugin開發的自動生成頁面骨架屏方案
- 安裝
page-skeleton-webpack-plugin
html-webpack-plugin
npm install --save-dev page-skeleton-webpack-plugin //這個包有140M 需要注意是否成功下載
npm install --save-dev html-webpack-plugin
- 配置插件
這裏使用的vue-cli3
,故先新建文件vue.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const SkeletonPlugin = require('page-skeleton-webpack-plugin').SkeletonPlugin
const path = require('path')
module.exports = {
configureWebpack: {
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'public/index.html'
}),
new SkeletonPlugin({
pathname: path.resolve(__dirname, `./shell`), // 用來存儲 shell 文件的地址
staticDir: path.resolve(__dirname, './dist'), // 最好和 `output.path` 相同
routes: ['/', '/about'] // 將需要生成骨架屏的路由添加到數組中
})
]
}
}
- 修改HTML Webpack Plugin 插件的模板
因爲我們的項目用的是vue-cli腳手架創建的,所以修改public/index.html
內容,修改如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>vue-skeleton</title>
</head>
<body>
<noscript>
<strong>We're sorry but vue-skeleton doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
<!-- shell -->
</div>
<!-- built files will be auto injected -->
</body>
</html>
重點是 <!-- shell -->
,因爲插件是根據這個來找到往哪個DOM節點下面動態的插入骨架屏的html文件的。
- 重啓項目
可以打開控制檯,看到有如下提示說明插件已經正常運行了
- 啓動插件
在開發頁面中通過 Ctrl|Cmd + enter 呼出插件交互界面,或者在在瀏覽器的 JavaScript 控制檯內輸入toggleBar呼出交互界面。點擊交互界面中的按鈕,進行骨架頁面的預覽,這一過程可能會花費 20s 左右時間,當插件準備好骨架頁面後,會自動通過瀏覽器打開預覽頁面,如下圖。