当前位置: 移动技术网 > IT编程>脚本编程>vue.js > 关于Vue单页面骨架屏实践记录

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

2018年02月24日  | 移动技术网IT编程  | 我要评论

神话放送130616,厦门户外,上海电视大学嘉定分校

关于骨架屏介绍

骨架屏的作用主要是在网络请求较慢时,提供基础占位,当数据加载完成,恢复数据展示。这样给用户一种很自然的过渡,不会造成页面长时间白屏或者闪烁等情况。 常见的骨架屏实现方案有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

总结

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网