关于Vue单页面骨架屏实践记录
关于骨架屏介绍
骨架屏的作用主要是在网络请求较慢时,提供基础占位,当数据加载完成,恢复数据展示。这样给用户一种很自然的过渡,不会造成页面长时间白屏或者闪烁等情况。 常见的骨架屏实现方案有ssr服务端渲染和prerender两种解决方案。
这里主要通过代码为大家展示如何一步步做出这样一个骨架屏:
prerender 渲染骨架屏
本组件库骨架屏的实现也是基于预渲染去实现的,有关于预渲染更详细的介绍请参考这篇文章:处理 vue 单页面 meta seo的另一种思路 下面我们主要介绍其实现步骤,首先我们也是需要配置webpack-plugin,不过已经有实现好的prerender-spa-plugin可用
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
<template> <div class="main-skeleton"> <w-skeleton height="80px"></w-skeleton> <div> <div class="skeleton-container"> <div class="skeleton"> <w-skeleton height="300px"></w-skeleton> </div> <w-skeleton height="45px"></w-skeleton> </div> <div class="skeleton-bottom"> <w-skeleton height="45px"></w-skeleton> </div> </div> </div> </template>
当初次进入页面的时候我们需要显示骨架屏,数据加载完,我们需要移除骨架屏:
<template> <div id="app"> <mainskeleton v-if="!init"></mainskeleton> <div v-else> <div class="body"></div> </div> </div> </template> <script> import mainskeleton from './main.skeleton.vue' export default { name: 'app', data () { return { init: false } }, mounted () { // 这里模拟数据请求 settimeout(() => { this.init = true }, 250) }, components: { mainskeleton } } </script>
ssr 渲染骨架屏
下面我用我灵魂画师的笔法,画出了大致的过程:
首先创建我们的skeleton.entry.js
import vue from 'vue'; import skeleton from './skeleton.vue'; export default new vue({ components: { skeleton }, template: '<skeleton />' });
当然这里的skeleton.vue使我们事先写好的骨架屏组件,看起来可能是这样:
<template> <div class="skeleton-wrapper"> <header class="skeleton-header"></header> <div class="skeleton-block"></div> </div> </template>
然后我们需要的是能把skeleton.entry.js编译成服务端渲染可用的bundle文件,所以我们需要有个编译骨架屏的webpack.ssr.conf.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片段,这里贴出核心代码:
// 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({}, function (err, skeletonhtml) { if (err) { reject(err); } else { resolve({skeletonhtml: skeletonhtml, skeletoncss: skeletoncss}); } }); });
最后一步,我们对产出的html片段, css片段进行组装,产出最终的html,所以我们需要监听webpack 的编译挂载之前的事件:
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('</head>'); htmlplugindata.html = insertat(htmlplugindata.html, ("<style>" + skeletoncss + "</style>"), 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 地址: vv-ui/vv-ui
演示地址: vv-ui
文档地址:skeleton
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
上一篇: 深睿@CMEF I深睿告诉你,AI+医疗是怎样的体验
下一篇: 详解vue-cli 接口代理配置