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


Posted in Javascript onDecember 13, 2017

关于骨架屏介绍

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

总结

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

Javascript 相关文章推荐
9行javascript代码获取QQ群成员具体实现
Oct 16 Javascript
JavaScript严格模式禁用With语句的原因
Oct 20 Javascript
javascript面向对象之定义成员方法实例分析
Jan 13 Javascript
js分页工具实例
Jan 28 Javascript
jQuery仿京东商城楼梯式导航定位菜单
Jul 25 Javascript
JS获取和修改元素样式的实例代码
Aug 06 Javascript
js实现颜色阶梯渐变效果(Gradient算法)
Mar 21 Javascript
vue实现个人信息查看和密码修改功能
May 06 Javascript
layui动态渲染生成select的option值方法
Sep 23 Javascript
JavaScript 常见的继承方式汇总
Sep 17 Javascript
js获取url页面id,也就是最后的数字文件名
Sep 25 Javascript
Vue的列表之渲染,排序,过滤详解
Feb 24 Vue.js
JS实现利用两个队列表示一个栈的方法
Dec 13 #Javascript
node vue项目开发之前后端分离实战记录
Dec 13 #Javascript
详解vue-cli快速构建vue应用并实现webpack打包
Dec 13 #Javascript
Angularjs过滤器实现动态搜索与排序功能示例
Dec 13 #Javascript
Angular4编程之表单响应功能示例
Dec 13 #Javascript
详解webpack require.ensure与require AMD的区别
Dec 13 #Javascript
vue登录路由验证的实现
Dec 13 #Javascript
You might like
php 带逗号千位符数字的处理方法
2012/01/10 PHP
PHP数组循环操作详细介绍 附实例代码
2013/02/03 PHP
php截取指定2个字符之间字符串的方法
2015/04/15 PHP
PHP编程实现脚本异步执行的方法
2017/08/09 PHP
Laravel的Auth验证Token验证使用自定义Redis的例子
2019/09/30 PHP
解决jQuery插件tipswindown与hintbox冲突
2010/11/05 Javascript
JavaScript打印iframe内容示例代码
2013/08/20 Javascript
js实现目录定位正文示例
2013/11/14 Javascript
Js操作树节点自动折叠展开的几种方法
2014/05/05 Javascript
JS+CSS实现Div弹出窗口同时背景变暗的方法
2015/03/04 Javascript
jQuery的Scrollify插件实现滑动到页面下一节点
2015/07/05 Javascript
基于javascript代码实现通过点击图片显示原图片
2015/11/29 Javascript
vue.js利用Object.defineProperty实现双向绑定
2017/03/09 Javascript
jQuery获取table下某一行某一列的值实现代码
2017/04/07 jQuery
JQueryMiniUI按照时间进行查询的实现方法
2017/06/07 jQuery
解决html input验证只能输入数字,不能输入其他的问题
2017/07/21 Javascript
详解Angular2学习笔记之Html属性绑定
2018/01/03 Javascript
深入剖析Node.js cluster模块
2018/05/23 Javascript
vue 在methods中调用mounted的实现操作
2020/08/07 Javascript
vue从后台渲染文章列表以及根据id跳转文章详情详解
2020/12/14 Vue.js
Javascript实现打鼓效果
2021/01/29 Javascript
用javascript实现倒计时效果
2021/02/09 Javascript
python实现两个文件合并功能
2018/04/01 Python
基于python-opencv3的图像显示和保存操作
2019/06/27 Python
详解用Python为直方图绘制拟合曲线的两种方法
2019/08/21 Python
Django模板标签中url使用详解(url跳转到指定页面)
2020/03/19 Python
3种适用于Python的疯狂秘密武器及原因解析
2020/04/29 Python
在CentOS7下安装Python3教程解析
2020/07/09 Python
使用css实现android系统的loading加载动画
2019/07/25 HTML / CSS
HealthElement海外旗舰店:新西兰大卖场
2018/02/23 全球购物
澳大利亚婴儿喂养品牌:Cherub Baby
2018/11/01 全球购物
感恩之星事迹材料
2014/05/03 职场文书
2015年会计年终工作总结
2015/05/26 职场文书
Canvas跟随鼠标炫彩小球的实现
2021/04/11 Javascript
微信小程序用户授权最佳实践指南
2021/05/08 Javascript
opencv检测动态物体的实现
2021/07/21 Python