- 什么是骨架屏
image.png
- 为什么会有骨架屏的需求
都知道单页面应用有一个首屏加载慢的缺点。。
- 慢会带来什么后果?
- 首次加载白屏时间长(量太大,渲染慢)
- 首屏加载卡顿(加载一半,卡主一半)
- 导致用户体验非常不好
- 解决方案
- 服务器端渲染(SSR):服务端渲染好页面,客户端就加载个html
- 使用骨架屏,提高用户体验
- 思路
需要在vue的执行js代码加载之前,先让用户看到骨架屏,待app代码执行 new Vue() 替换<div id="app"></div> 就好了
- 思路有了,接下来实现自己的想法
决定加载js文件的是html,操作html的插件是html-webpack-plugin,
于是可以自定义插件在其后操作,根据插件提供的数据入口获取并更改数据
- 具体实现
- 写一个自己的插件
MyPlugin.js
, 放在util
目录或者根目录下:
function MyPlugin(options) { //{ text:'xxx' }
// 个性化定制
this.options = options;
if ( !this.options.text ) {
throw new Error('text is required!!!');
}
}
MyPlugin.prototype.apply = function(compiler) {
// 编辑过程事件回调函数
compiler.plugin('compilation',(compilation)=>{
console.log(this.options.text);
// 通过compilation操作文件
compilation.assets['./test.txt'] = {
// 内容
source:()=> {
return this.options.text;
},
// 大小
size:()=>{
return this.options.text.length;
}
}
// 通过compilation切入其他组件提供的事件
compilation.plugin('html-webpack-plugin-before-html-processing',(htmlData,callback) => {
// console.log(htmlData.html);
htmlData.html = htmlData.html.replace('<div id="app"></div>',`
<div id="app">
<div style="background-color:red;height:300px;display:none;" id="default" >
我是默认的骨架屏
</div>
<div style="background-color:red;height:300px;display:none;" id="user" >
我是user的骨架屏
</div>
<div style="background-color:red;height:300px;display:none;" id="login" >
我是login的骨架屏
</div>
</div>
<script>
var hash = window.location.hash;
var path = window.location.pathname;
if (path === '/login' || hash === '#/login') {
document.getElementById('login').style.display = 'block';
} else if (path === '/user' || hash === '#/user') {
document.getElementById('user').style.display = 'block';
} else {
document.getElementById('default').style.display = 'block';
}
</script>`);
callback(null, htmlData);
// 错误优先
// 如果处理有错误,传递到第一个参数,否则错误参数的位置就null
// 没有成功的生成文件是因为没有调用回调函数
});
});
}
module.exports = MyPlugin;
自定义插件参考官方文档:https://github.com/jantimon/html-webpack-plugin#third-party-addons
自定插件
- 在
config.webpack.js
中引入自己的插件
//...
const MyPlugin require('./MyPlugin.js')
modules.exports = {
// ...
plugins: [
new htmlWebpackPlugin({...}),
// 在htmlWebpackPlugin之后
new MyPlugin({
text: '自定义内容' // 不需要可以不定义
})
]
}