Vue页面显示骨架屏
1.什么是骨架屏幕?
在页面加载数据之前,有一段空白时间,要么用loading加载,要么就用骨架屏。

2.如何快速用Vue实现骨架屏效果?
#①直接把下面的CSS代码复制,粘贴到vue项目的index.html 的<head>...</head>里面
<style>
.skeleton {
position: fixed;
height: 100%;
overflow: hidden;
padding: 15px;
box-sizing: border-box;
background: #fff;
width: 98%;
top: 0;
}
.skeleton-nav {
height: 110px;
background: #eee;
margin-bottom: 15px;
}
.skeleton-swiper {
height: 440px;
background: #eee;
margin-bottom: 15px;
}
.skeleton-tabs {
list-style: none;
padding: 0;
margin: 0 -15px;
display: flex;
flex-wrap: wrap;
}
.skeleton-tabs-item {
width: 22%;
height: 80px;
box-sizing: border-box;
text-align: center;
margin-bottom: 15px;
}
.skeleton-tabs-item span {
display: inline-block;
width: 80px;
height: 80px;
border-radius: 55px;
background: #eee;
}
.skeleton-banner {
height: 250px;
background: #eee;
margin-bottom: 15px;
}
.skeleton-productions {
height: 50px;
margin-bottom: 15px;
background: #eee;
}
</style>#②把下面的html代码复制,粘贴到vue项目的index.html 的 <div id=app>.....</div>里面
1 <div data-server-rendered=true class="skeleton page">
2 <div class=skeleton-nav></div>
3 <div class=skeleton-swiper></div>
4 <ul class=skeleton-tabs>
5 <li class=skeleton-tabs-item><span></span></li>
6 <li class=skeleton-tabs-item><span></span></li>
7 <li class=skeleton-tabs-item><span></span></li>
8 <li class=skeleton-tabs-item><span></span></li>
9 <li class=skeleton-tabs-item><span></span></li>
10 <li class=skeleton-tabs-item><span></span></li>
11 <li class=skeleton-tabs-item><span></span></li>
12 <li class=skeleton-tabs-item><span></span></li>
13 </ul>
14 <div class=skeleton-banner></div>
15 <div class=skeleton-productions></div>
16 <div class=skeleton-productions></div>
17 <div class=skeleton-productions></div>
18 <div class=skeleton-productions></div>
19 <ul class=skeleton-tabs>
20 <li class=skeleton-tabs-item><span></span></li>
21 <li class=skeleton-tabs-item><span></span></li>
22 <li class=skeleton-tabs-item><span></span></li>
23 <li class=skeleton-tabs-item><span></span></li>
24 <li class=skeleton-tabs-item><span></span></li>
25 <li class=skeleton-tabs-item><span></span></li>
26 <li class=skeleton-tabs-item><span></span></li>
27 <li class=skeleton-tabs-item><span></span></li>
28 </ul>
29 <div class=skeleton-swiper></div>
30 <div class=skeleton-nav></div>
31 </div>#③如果你是vue-cli脚手架搭的,直接就可以看到效果了,然后npm run build。就成了。
下图是我做的效果。

3.既然来到了这里,我们肯定要知道原理的。
感谢作者的分享: 附上链接
原理:
DOM里面有且仅有一个div#app,当js被执行完成之后,此div#app会被整个替换掉,也就是“测试测试测试测试测试测试测试测试”这部分内容,会被替换掉。
所以:我们写在里面的html代码首屏时会显示,但DOM经过render渲染结束后,里面就被替换了。
如下代码:是index.html里面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue-skeleton</title>
</head>
<body>
<div id="app">
测试测试测试测试测试测试测试测试
</div>
<script src="/dist/build.js"></script>
</body>
</html>4.如何从无到有些一个骨架屏
①通过vue-cli安装一个简易版的vue项目
vue init webpack-simple vue-skeleton②安装第一次插件:
npm install vue-server-renderer --save
//安装服务端渲染插件,利用它能够把.vue文件处理成html和css字符串的功能,来完成骨架屏的注入
npm install webpack-node-externals --save-dev
//安装外部插件,在项目中给css设置白名单npm install html-webpack-plugin --save-dev //打包的时候可以将index.html一起打包 ③在/src目录下新建一个Skeleton.vue文件,样式都可以自己定义的,为了方便,可以直接复制粘贴。
1 <template>
2 <div class="skeleton page">
3 <div class="skeleton-nav"></div>
4 <div class="skeleton-swiper"></div>
5 <ul class="skeleton-tabs">
6 <li v-for="i in 8" class="skeleton-tabs-item"><span></span></li>
7 </ul>
8 <div class="skeleton-banner"></div>
9 <div v-for="i in 4" class="skeleton-productions"></div>
10 <ul class="skeleton-tabs">
11 <li v-for="i in 8" class="skeleton-tabs-item"><span></span></li>
12 </ul>
13 <div class="skeleton-swiper"></div>
14 <div class="skeleton-nav"></div>
15 </div>
16 </template>
17
18 <style>
19 .skeleton {
20 position: fixed;
21 height: 100%;
22 overflow: hidden;
23 padding: 15px;
24 box-sizing: border-box;
25 background: #fff;
26 width: 98%;
27 top: 0;
28 }
29 .skeleton-nav {
30 height: 110px;
31 background: #eee;
32 margin-bottom: 15px;
33 }
34 .skeleton-swiper {
35 height: 440px;
36 background: #eee;
37 margin-bottom: 15px;
38 }
39 .skeleton-tabs {
40 list-style: none;
41 padding: 0;
42 margin: 0 -15px;
43 display: flex;
44 flex-wrap: wrap;
45 }
46 .skeleton-tabs-item {
47 width: 22%;
48 height: 80px;
49 box-sizing: border-box;
50 text-align: center;
51 margin-bottom: 15px;
52 }
53 .skeleton-tabs-item span {
54 display: inline-block;
55 width: 80px;
56 height: 80px;
57 border-radius: 55px;
58 background: #eee;
59 }
60 .skeleton-banner {
61 height: 250px;
62 background: #eee;
63 margin-bottom: 15px;
64 }
65 .skeleton-productions {
66 height: 50px;
67 margin-bottom: 15px;
68 background: #eee;
69 }
70 </style> ④在Skeleton.vue同个目录下,建立一个skeleton.entry.js入口文件
1 import Vue from 'vue'
2 import Skeleton from './Skeleton.vue'
3
4 export default new Vue({
5 components: {
6 Skeleton
7 },
8 template: '<skeleton />'
9 }) ⑤在根目录新建一个webpack.skeleton.conf.js文件,以专门用来进行骨架屏的构建,vue-server-renderer就是将Skeleton.vue生成json文件,以便插入到html。
该配置文件和普通的配置文件基本完全一致,主要的区别在于其target: 'node',配置了externals,以及在plugins里面加入了VueSSRServerPlugin。在VueSSRServerPlugin中,
指定了其输出的json文件名。我们可以通过运行下列指令,在/dist目录下生成一个skeleton.json文件
const path = require('path')
const webpack = require('webpack')
const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = { target: 'node', entry: { skeleton: './src/skeleton.entry.js' },
output: { path: path.resolve(__dirname, './dist'), publicPath: '/dist/', filename: '[name].js', libraryTarget: 'commonjs2' },plugins: [
new HtmlWebpackPlugin(
{
title: 'test',
template: 'index.html',
}
)
],module: { rules: [ { test: /\.css$/, use: [ 'vue-style-loader', 'css-loader' ] }, { test: /\.vue$/, loader: 'vue-loader' } ] }, externals: nodeExternals({ whitelist: /\.css$/ }), resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' }, extensions: ['*', '.js', '.vue', '.json'] }, plugins: [ new VueSSRServerPlugin({ filename: 'skeleton.json' }) ] }⑥使用命令 将skeleton.vue文件变成json格式
webpack --config ./webpack.skeleton.conf.js ⑦在根目录下新建一个skeleton.js,该文件即将被用于往index.html内插入骨架屏
1 const fs = require('fs')
2 const { resolve } = require('path')
3
4 const createBundleRenderer = require('vue-server-renderer').createBundleRenderer
5
6 // 读取`skeleton.json`,以`index.html`为模板写入内容
7 const renderer = createBundleRenderer(resolve(__dirname, './dist/skeleton.json'), {
8 template: fs.readFileSync(resolve(__dirname, './index.html'), 'utf-8')
9 })
10
11 // 把上一步模板完成的内容写入(替换)`index.html`
12 renderer.renderToString({}, (err, html) => {
13 fs.writeFileSync('index.html', html, 'utf-8')
14 }) ⑧将<!--vue-ssr-outlet-->占位符写在index.html里面,才能注入代码
<div id="app">
<!--vue-ssr-outlet-->
</div> ⑨最后,只要运行node skeleton.js,就可以完成骨架屏的注入了。可以看下index.html的结果。
⑩进一步处理,把这些内容都压缩一下,改写skeleton.js
1 ...
2
3 + const htmlMinifier = require('html-minifier')
4
5 ...
6
7 renderer.renderToString({}, (err, html) => {
8 + html = htmlMinifier.minify(html, {
9 + collapseWhitespace: true,
10 + minifyCSS: true
11 + })
12 fs.writeFileSync('index.html', html, 'utf-8')
13 })
















