github 地址: VV-UI/VV-UI

演示地址: vv-ui

文档地址:skeleton

关于骨架屏介绍

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

  

关于:

作者:monkeyWang

本文参考文章:为vue项目添加骨架屏

本文源码详见:VV-UI/VV-UI

本人主页:monkeyWang

微信公众号:前端知识铺

会不定期推送前端技术文章,欢迎关注

Vue单页面骨架屏实践的更多相关文章

  1. Vue页面骨架屏(二)

    实现思路 参考原文中在构建时使用 Vue 预渲染骨架屏一节介绍的思路,我将骨架屏也看成路由组件,在构建时使用 Vue 预渲染功能,将骨架屏组件的渲染结果 HTML 片段插入 HTML 页面模版的挂载点 ...

  2. 关于处理移动端Vue单页面及其内嵌兼容问题

    关于处理移动端Vue单页面及其内嵌兼容问题 question:由于最近转移了以前的H5项目,重构使用Vue单页面,导致部分手机内嵌或在微信浏览器中无法浏览,或者无法使用ajax请求:手机机型千变万化, ...

  3. 处理 Vue 单页面应用 SEO 的另一种思路

    vue-meta-info 官方地址: monkeyWangs/vue-meta-info (设置vue 单页面meta info信息,如果需要单页面SEO,可以和 prerender-spa-plu ...

  4. vue单页面打包文件大?首次加载慢?按需加载?是你打开方式不对

    部署各vue项目,走了一遍坑.... vue单页面应用刷新404 找到nginx多网站配置文件:类似nginx/sites-available/www.baidu.com server { liste ...

  5. [one day one question] Vue单页面应用如何保证F5强刷不清空数据

    问题描述: Vue单页面用按F5强刷,数据就恢复初始了,这怎么破? 解决方案: store.subscribe((mutation, state) => { sessionStorage.set ...

  6. [转] 2017-11-20 发布 另辟蹊径:vue单页面,多路由,前进刷新,后退不刷新

    目的:vue-cli构建的vue单页面应用,某些特定的页面,实现前进刷新,后退不刷新,类似app般的用户体验.注: 此处的刷新特指当进入此页面时,触发ajax请求,向服务器获取数据.不刷新特指当进入此 ...

  7. vue单页面处理SEO问题

    设置vue 单页面meta info信息 vue-meta-info,(https://github.com/muwoo/vue-meta-info)如果需要单页面SEO,可以和 prerender- ...

  8. Vue单页面应用阻止浏览器记住密码

    Vue单页面应用阻止浏览器记住密码 ——IT唐伯虎 摘要: Vue单页面应用阻止浏览器记住密码. 现象1:路由切换时再次提示“是否记住密码” 登录页面有个密码输入框,输入账号密码进行登录: 登录完成后 ...

  9. 另辟蹊径:vue单页面,多路由,前进刷新,后退不刷新

    目的:vue-cli构建的vue单页面应用,某些特定的页面,实现前进刷新,后退不刷新,类似app般的用户体验.注: 此处的刷新特指当进入此页面时,触发ajax请求,向服务器获取数据.不刷新特指当进入此 ...

随机推荐

  1. css3+div画大风车

    今天已经礼拜三了,周天小颖家的佩佩就要结婚啦,小颖要去当伴娘了,哈哈哈哈哈哈,想想都觉得乐开了花,不过之前她给我说让我当她伴娘时,我说我要减肥,不然她那么瘦弱,我站旁边就感觉像一个圆滚滚的小皮球,小颖 ...

  2. 基于HTML5 Canvas的3D动态Chart图表

    发现现在工业SCADA上或者电信网管方面用图表的特别多,虽然绝大部分人在图表制作方面用的是echarts,他确实好用,但是有些时候我们不能调用别的插件,这个时候就得自己写这些美丽的图表了,然而图表轻易 ...

  3. hadoop2的mapreduce操作hbase数据

    1.从hbase中取数据,再把计算结果插入hbase中 package com.yeliang; import java.io.IOException; import org.apache.hadoo ...

  4. ubuntu 常用命令集

    一.安装的时候,让你输入代替root用户的名称与密码 使用sudo root切换root的时候会要求你输入密码,这时候你输入什么都不对的 要想使用的哈,需要给root设置密码,命令如下: sudo p ...

  5. Grunt参考

    Grunt参考: http://www.cnblogs.com/yexiaochai/p/3603389.html http://blog.csdn.net/wangfupeng1988/articl ...

  6. struts2运行过程(图解)

    .................................................................................................... ...

  7. day2--SecureCRT的配置

    生产中,我们是看不到虚拟机的工作界面,虚拟机的界面相当于机房显示屏的样子,实际上我们是在操作工具里面进行管理,这里使用SecureCRT远程连接虚拟机,SecureCRT的设置如下: 1.打开Secu ...

  8. Struts2-Tiles整合

    Apache Tiles是一个JavaEE应用的页面布局框架.Tiles框架提供了一种模板机制,可以为某一类页面定义一个通用的模板,该模板定义了页面的整体布局.布局由可以复用的多个块组成,每个页面可以 ...

  9. solr索引库的创建

    solr索引库的创建 一.找到你安装的[solrhome]目录(我的是这个) 二.进入该目录 三.选择其中任意一个索引库复制一份到该目录下并更名为要创建的索引库名称 四.进入[myindex]目录下, ...

  10. [转载] Lucene 工作原理

    转载自http://www.cnblogs.com/dewin/archive/2009/11/24/1609905.html Lucene是一个高性能的java全文检索工具包,它使用的是倒排文件索引 ...