Vue中实现⾻架屏的多种⽅式
vue-cli项⽬⾸页加载缓慢想要使⽤⾻架屏效果,经过⼏天的实践,这⾥学习并记录⼀下vue项⽬⾃动⽣成⾻架屏⽅法。
前⾔:⾻架屏的作⽤主要是在⽹络请求较慢时,提供基础占位,当数据加载完成,恢复数据展⽰。这样给⽤户⼀种很⾃然的过渡,不会造成页⾯长时间⽩屏或者闪烁等情况。常
见的⾻架屏实现⽅案有ssr服务端渲染和prerender两种解决⽅案。
1、⼿动编写⾻架屏代码(页⾯简单少推荐)
该⽅法就是⼿动编写项⽬index.html ⼊⼝⽂件,实现在vue项⽬初始化展⽰替换div#app根元素前的⾻架屏效果。
2.通过预渲染⼿动书写的代码⽣成相应的⾻架屏(页⾯简单少推荐)
⽐如:vue-skeleton-webpack-plugin  ⾃动⽣成并⾃动插⼊静态⾻架屏
以webpack4构建的项⽬为例开始撸代码:
基于 Vue Webpack 模板应⽤这个插件的例⼦: SPA 中单个 Skeleton:
1. npm install vue-skeleton-webpack-plugin 安装插件
2. 在 webpack 中引⼊插件:以4版本为例配置如下 fig.js
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin');
const path = require('path')
publicPath:'./',
devServer: {
proxy: {
'/api':{
target: '192.168.0.3:8123',
/
/ target: '192.168.3.20:8154/',
changeOrigin: true,
pathRewrite: {
'^/api': '/api'
}
},
},
disableHostCheck: true
},
chainWebpack: config => {
// 其他配置
<('main').add('babel-polyfill') // main是⼊⼝js⽂件
// 其他配置
},
css: {
extract: true, // css拆分ExtractTextPlugin插件,默认true - ⾻架屏需要为true
},
lintOnSave: false,
configureWebpack: (config) => {
// vue⾻架屏插件配置
config.plugins.push(new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, './src/components/entry-skeleton.js'),
},
},
minimize: true,
quiet: true,
}))
},
};
上⾯红⾊的那⾏配置的是⾻架屏的⼊⼝⽂件
⾻架屏的组件如下:这是⽬录
entry-skeleton.js
import Vue from 'vue';
import Skeleton from './Skeleton';
export default new Vue({
components: {
Skeleton
},
template: '<skeleton />'
});
  Skeleton.vue    这⾥⾯可以画出⾃⼰适合的⾻架拼样⼦
<template>
<div class="skeleton-wrapper">
<header class="skeleton-header"></header>
<section class="skeleton-block">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPj            <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPj        </section>
react router 和vue router
</div>
</template>
<script>
export default {
name: 'skeleton'
};
</script>
<style scoped>
.skeleton-header {
height: 152px;
background: grey;
margin-top: 60px;
width: 152px;
margin: 60px auto;
}
.skeleton-block {
display: flex;
flex-direction: column;
padding-top: 8px;
}
</style>
预加载时:
加载后:
⾻架屏的具体展现是需要⾃⼰画的这个实践只是对于 SPA 中单个 Skeleton
下⾯同样以这个为例去实践SPA 中多个 Skeleton,以给单页⾯的不同路由设置不同的⾻架屏,也可以给多页⾯设置,同时为了开发时调试⽅便,会将⾻架屏作为路由写⼊ router 中,可谓是相当体贴了。
同样的重复上⾯的第⼀步
第⼆步在配置webpack的时候稍微有点不同
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin');
const path = require('path')
publicPath:'./' ,
devServer: {
proxy: {
'/api':{
target: 'i.yd-jxt',
// target: '192.168.3.20:8154/',
changeOrigin: true,
pathRewrite: {
'^/api': '/v2'
}
},
},
disableHostCheck: true
},
chainWebpack: config => {
// 其他配置
<('main').add('babel-polyfill') // main是⼊⼝js⽂件
// 其他配置
},
lintOnSave: false,
configureWebpack: (config) => {
// vue⾻架屏插件配置
config.plugins.push(new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, './entry-skeleton.js'),
},
},
minimize: true,
quiet: true,
router: {
mode: 'hash',
routes: [{
path: '/about',
skeletonId: 'skeleton1'
},
{
path: '/',
skeletonId: 'skeleton2'
},
]
}
}))
},
};
上⾯着⾊的这段代码就是分路由展现不同的⾻架屏页⾯
这是⾻架屏⼊⼝⽂件配置
import Vue from 'vue';
import Skeleton1 from '@/components/skeleton/Skeleton1';
import Skeleton2 from '@/components/skeleton/Skeleton2';
export default new Vue({
components: {
Skeleton1,
Skeleton2
},
template: `
<div>
<skeleton1 id="skeleton1" />
<skeleton2 id="skeleton2" />
</div>
});
路由组件⾻架屏页⾯
缺点:vue-skeleton-webpack-plugin 样式不能根据内容⽣成⾻架屏,是⼀开始写的什么就是什么,灵活度不⾼。第⼀种⽅式也是
看到这⾥相信都知道了如何在项⽬⾥如何使⽤去实现⾻架屏的加载,但是这样的⽅式去实现⾻架屏加载很明显的
有个弊端就是每个路由页⾯都需要出对应的图然后前端还要⾃⼰绘制⼀遍,要是有⼀个能够根据页⾯结构⾃⼰⽣成相应页⾯的⾻架屏的⽅法就好了。
3.饿了么内部的⽣成⾻架页⾯的⼯具 page-skeleton-webpack-plugin(不推荐)
原理:
在等待页⾯加载
渲染完成之后,在保留页⾯布局样式的前提下,通过对页⾯中元素进⾏删减或增添,对已有元素通过层叠样
式进⾏覆盖,这样达到在不改变页⾯布局下,隐藏图⽚和⽂字,通过样式覆盖,使得其展⽰为灰⾊块。然后
将修改后的 HTML 和 CSS 样式提取出来,这样就是⾻架屏了.
缺点:
对于复杂的页⾯也会有不尽如⼈意的地⽅
⽣成的⾻架屏节点是基于页⾯本⾝的结构和 CSS,存在嵌套⽐较深的情况,体积不会太⼩
只⽀持 history 模式
⽬前已经没有⼈进⾏维护,不⽀持该种⽅式实现
4.css实现⾻架屏(⽐较简单的⼀种⽅式推荐)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
@-webkit-keyframes skeleton-ani {
0% {
left: -90%
}
to {
left: 120%
}
}
@keyframes skeleton-ani {
0% {
left: -90%
}
to {
left: 120%
}
}
.skt-loading .skeleton {
position: relative;
overflow: hidden;
border: none !important;
border-radius: 5px;
background-color: rgba(0, 0, 0, 0) !important;
background-image: none !important;
pointer-events: none;
}
.skt-loading .skeleton:after {
content: "";
position: absolute;
left: 0;
top: 0;
z-index: 9;
width: 100%;
height: 100%;
background-color: #ebf1f8;
display: block
}
.skt-loading .skeleton:not(.not-round):after {
border-radius: 4px
}
.skt-loading .skeleton:not(.not-before):before {
position: absolute;
top: 0;
width: 30%;
height: 100%;
content: "";
background: -webkit-gradient(linear, left top, right top, color-stop(0, hsla(0, 0%, 100%, 0)), color-stop(50%, hsla(0, 0%, 100%, .3)), to(hsla(0, 0%, 100%, 0)));
background: -o-linear-gradient(left, hsla(0, 0%, 100%, 0) 0, hsla(0, 0%, 100%, .3) 50%, hsla(0, 0%, 100%, 0) 100%);
background: linear-gradient(90deg, hsla(0, 0%, 100%, 0) 0, hsla(0, 0%, 100%, .3) 50%, hsla(0, 0%, 100%, 0));
-webkit-transform: skewX(-45deg);
-ms-transform: skewX(-45deg);
transform: skewX(-45deg);
z-index: 99;
-webkit-animation: skeleton-ani 1s ease infinite;
animation: skeleton-ani 1s ease infinite;
display: block
}
.skt-loading .skeleton.badge:after {
background-color: #f8fafc
}
input {
border: 1px solid #dcdcdc;
width: 100%;
}
</style>
</head>
<body>
<div id="skt-main" class="skt-loading">
<form>
<label class="skeleton">姓名:</label>
<div class="skeleton">
<input type="text" name="">
</div>
<br>
<label class="skeleton">爱好:</label>
<div class="skeleton">
<input type="text" name="">
</div>
</form>
</div>
<script>
setTimeout(() => {
var $sktmain = ElementById('skt-main');
$sktmain.className = $place('skt-loading', '')
}, 2000)
</script>
</body>
</html>
5.⽤纯 DOM 的⽅式结合 Puppeteer ⾃动⽣成⽹页⾻架屏
(⽐较靠谱的⼀种⽅式推荐)
⾃动⽣成⽹页⾻架屏(⽐较靠谱的⼀种⽅式
该⽅法需要下载【npm i draw-page-structure -g】,⽤纯 DOM 的⽅式结合 Puppeteer ⾃动⽣成⽹页⾻架屏,原理是:
⽣成操作Dom的JavaScript脚本(该脚本⽤于将项⽬页⾯转换成⾊块形式的⾻架屏效果);
通过Puppeteer控制⾕歌浏览器运⾏项⽬页⾯并获取页⾯、将上⼀步的脚本注⼊该页⾯,并⽣成⾻架屏所需的Dom节点;
将⾃动⽣成的⾻架屏Dom⽚段插⼊到应⽤页⾯的根⼊⼝节点。
使⽤注意事项:
核⼼在于 DOM 操作,puppeteer 仅提供运⾏环境和导出⽅式
只要能访问的页⾯都能⽣成,history 与 hash 模式⽆限制
不受项⽬和框架的限制,vue 和 react 等项⽬零修改即可复⽤
⽣成⾊块的单位为百分⽐,不同设备⾃适应
不需要 css-tree 来提取样式,不依赖页⾯本⾝的布局结构,⽣成扁平的 DOM 节点体积特别⼩
⽀持⾃定义⽣成⽅式与导出⽅式
dps插件使⽤步骤:
1、使⽤命令【npm i draw-page-structure -g】安装插件
2、dps init⽣成配置⽂件fig.js
3、修改fig.js进⾏相关配置,包括想渲染的页⾯url、通过includeElement和init⽅法调整⾻架屏效果等;
⼀般来说,你需要按⾃⼰的项⽬情况来配置 fig.js ,常见的配置项有:
url: 待⽣成⾻架屏的页⾯地址
output.filepath: ⽣成的⾻架屏节点写⼊的⽂件
output.injectSelector: ⾻架屏节点插⼊的位置,默认 #app
background: ⾻架屏主题⾊
animation: css3 动画属性
rootNode: 真对某个模块⽣成⾻架屏
device: 设备类型,默认 mobile
extraHTTPHeaders: 添加请求头
init: 开始⽣成之前的操作
includeElement(node, draw): 定制某个节点如何⽣成
writePageStructure(html, filepath): 回调的⾻架屏节点
4、dps start开始⽣成⾻架屏
编写操作 DOM 的 Javascript 脚本步骤:
遍历可见区域可见的 DOM 节点
包括:⾮隐藏元素、宽⾼⼤于 0 的元素、⾮透明元素、内容不是空格的元素、位于浏览窗⼝可见区域内的元素
针对(背景)图⽚、⽂字、表单项、⾳频视频等区域,算出其所占区域的宽、⾼、距离视⼝的绝对距离等信息
对于符合⽣成条件的区域,⼀视同仁,⽣成相应区域的颜⾊块
“⼀视同仁”即对于符合条件的区域,不区分具体元素,不⽤考虑结构层级,不考虑样式,统⼀⽣成 div 的颜⾊块
该脚本的运⾏环境决定了获取到的元素尺⼨与相关距离单位不可控,可能需要做转换,⽐如⽤的 rem、
em、vh 等;我们采⽤⽐较简单的⽅式,不取 style 的尺⼨相关的值,⽽是通过 getBoundingClientRect 获取宽、⾼、距离视⼝距离的绝对值,与当前设备的宽⾼,计算出相应的百分⽐作为颜⾊块的单位,这样来适配不同设备对于页⾯结构⽐较复杂或者⼤图⽚⽐较多的页⾯,会出现不尽如⼈意的地⽅,我们通过 includeElement(node, draw)和 init 两个钩⼦函数来⽀持⾃定义的微调
以上就能够直接跑在浏览器⽣成⾻架屏代码了,⼿动添加到应⽤页⾯
注意vue-cli4dps start 绘制出来的⽂件html需要替换public⽂件下⾯的html⽂件,当前前提是你没有特意设置⽣成后的⽂件路径,默认是在该项⽬⽂件下⾯,这个可解决上⾯⽅法的缺陷问题,相⽐之下已经⽐较友好,当然对于⼗分复杂的页⾯是需要⾃⼰在⽅法⾥⾯写⾃⼰指定渲染的东西,dps插件也有为此提供⽅法。
includeElement 和init这两个⽅法⾥⾯可以灵活控制。
关于⾻架屏的思考到这⾥并没有结束,未完待续。。。。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。