欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-28 10:07:32
关于骨架屏介绍 骨架屏的作用主要是在网络请求较慢时,提供基础占位,当数据加载完成,恢复数据展示。这样给用户一种很自然的过渡,不会造成页面长时间白屏或者闪烁等情况。 常...

关于骨架屏介绍

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

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

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

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 渲染骨架屏

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

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

首先创建我们的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

总结

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