关于Vue单页面骨架屏实践记录

关于骨架屏介绍

骨架屏的作用主要是在网络请求较慢时,提供基础占位,当数据加载完成,恢复数据展示。这样给用户一种很自然的过渡,不会造成页面长时间白屏或者闪烁等情况。 常见的骨架屏实现方案有ssr服务端渲染和prerender两种解决方案。

这里主要通过代码为大家展示如何一步步做出这样一个骨架屏:

prerender 渲染骨架屏

本组件库骨架屏的实现也是基于预渲染去实现的,有关于预渲染更详细的介绍请参考这篇文章:处理 Vue 单页面 Meta SEO的另一种思路 下面我们主要介绍其实现步骤,首先我们也是需要配置webpack-plugin,不过已经有实现好的prerender-spa-plugin可用

rush:js;"> var path = require('path') var PrerenderSpaPlugin = require('prerender-spa-plugin') module.exports = { // ... plugins: [ new PrerenderSpaPlugin( // Absolute path to compiled SPA path.join(__dirname,'../dist'),// List of routes to prerender ['/'] ) ] }

然后写好我们的骨架屏文件main.skeleton.vue

rush:xhtml;">

当初次进入页面的时候我们需要显示骨架屏,数据加载完,我们需要移除骨架屏:

rush:xhtml;">

ssr 渲染骨架屏

下面我用我灵魂画师的笔法,画出了大致的过程:

首先创建我们的skeleton.entry.js

rush:js;"> import Vue from 'vue'; import Skeleton from './skeleton.vue'; export default new Vue({ components: { Skeleton },template: '' });

当然这里的skeleton.vue使我们事先写好的骨架屏组件,看起来可能是这样:

rush:xhtml;">

然后我们需要的是能把skeleton.entry.js编译成服务端渲染可用的bundle文件,所以我们需要有个编译骨架屏的webpack.ssr.conf.js文件:

rush:js;"> const path = require('path'); const merge = require('webpack-merge'); const baseWebpackConfig = require('./webpack.base.conf'); const nodeExternals = require('webpack-node-externals'); function resolve(dir) { return path.join(__dirname,dir); } module.exports = merge(baseWebpackConfig,{ target: 'node',devtool: false,entry: { app: resolve('./src/skeleton.entry.js') },output: Object.assign({},baseWebpackConfig.output,{ libraryTarget: 'commonjs2' }),externals: nodeExternals({ whitelist: /\.css$/ }),plugins: [] });

接下来最终的步骤,就是编写我们的webpackPlugin,我们期望我们的webpackPlugin可以帮我们把入口文件编译成bundle,然后再通过vue-server-renderer来render bundle,最终产出响应的html片段和css片段,这里贴出核心代码

rush:js;"> // webpack start to work var serverCompiler = webpack(serverWebpackConfig); var mfs = new MFS(); // output to mfs serverCompiler.outputFileSystem = mfs; serverCompiler.watch({},function (err,stats) {

if (err) {
reject(err);
return;
}
stats = stats.toJson();
stats.errors.forEach(function (err) {
console.error(err);
});
stats.warnings.forEach(function (err) {
console.warn(err);
});
var bundle = mfs.readFileSync(outputPath,'utf-8');
var skeletonCss = mfs.readFileSync(outputCsspath,'utf-8');
// create renderer with bundle
var renderer = createBundleRenderer(bundle);
// use vue ssr to render skeleton
renderer.renderToString({},skeletonHtml) {
if (err) {
reject(err);
}
else {
resolve({skeletonHtml: skeletonHtml,skeletonCss: skeletonCss});
}
});
});

最后一步,我们对产出的html片段,css片段进行组装,产出最终的html,所以我们需要监听webpack 的编译挂载之前的事件:

rush:js;"> compiler.plugin('compilation',function (compilation) { // add listener for html-webpack-plugin compilation.plugin('html-webpack-plugin-before-html-processing',function (htmlPluginData,callback) { ssr(webpackConfig).then(function (ref) { var skeletonHtml = ref.skeletonHtml; var skeletonCss = ref.skeletonCss; // insert inlined styles into html var headTagEndPos = htmlPluginData.html.lastIndexOf(''); htmlPluginData.html = insertAt(htmlPluginData.html,(""),headTagEndPos);

// replace mounted point with ssr result in html
var appPos = htmlPluginData.html.lastIndexOf(insertAfter) + insertAfter.length;
htmlPluginData.html = insertAt(htmlPluginData.html,skeletonHtml,appPos);
callback(null,htmlPluginData);
});
});
});

github 地址:

演示地址:

文档地址:nofollow" target="_blank" href="https://vv-ui.github.io/VV-UI/#/skeleton">skeleton

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对编程之家的支持

相关文章

可以通过min-width属性来设置el-table-column的最小宽度。以...
yarn dev,当文件变动后,会自动重启。 yanr start不会自动重...
ref 用于创建一个对值的响应式引用。这个值可以是原始值(如...
通过修改 getWK005 函数来实现这一点。这里的 query 参数就是...
<el-form-item label="入库类型" ...
API 变动 样式类名变化: 一些组件的样式类名有所变动,可能需...