现在的应用开发,基本上都是前后端分离的,前端主流框架有SPA、MPA等,那么解决页面渲染、白屏时间成为首要关注的点

webpack可以按需加载,减小首屏需要加载代码的体积;

使用CDN技术、静态代码等缓存技术,可以减小加载渲染的时长

问题:但是首页依然存在加载、渲染等待时长的问题。那么如何从视觉效果上减小首屏白屏的时间呢?

骨架屏:举个例子:其实就是在模版文件中id=app容器下面写想要展示的效果,在new Vue(option)之后,该id下的内容就被替换了( 这时候,可能Vue编译生成的内容还没有挂载。因为new Vue的时候会进行一系列的初始化,这也需要耗费时间的)。这样就可以从视觉上减小白屏的时间

骨架屏的实现方式

1、直接在模版文件id=app容器下面,写进想要展示的效果html

2、直接在模板文件id=app容器下面,用图片展示

3、使用vue ssr提供的webpack插件

4、自动生成并且自动插入静态骨架屏

方式1和方式2存在的缺陷:针对不同入口,展示的效果都一样,导致不能灵活的针对不同的入口,展示不同的样式

方式3可以针对不同的入口展示不同的效果。(实质也是先通过ssr生成一个json文件,然后将json文件内容注入到模板文件的id=app容器下)

方案一、直接在模版文件id=app容器下面,写进想要展示的效果html

在根目录的模版文件内写进内容,如红色圈出来的地方

在浏览器打开项目

在调用new Vue之前的展示效果(只是做了个简单效果,不喜勿喷):

可以看到elements中id=app的容器下内容,就是我们写进的骨架屏效果内容

在看下调了new Vue之后的效果,id=app容器下的内容被vue编译生成的内容替换了

方案二、直接在模板文件id=app容器下面,用图片展示(这个就不做展示了)

方案三、使用vue ssr提供的webpack插件:即用.vue文件完成骨架屏

在方案一的基础上,将骨架屏的代码抽离出来,不在模版文件里面书写代码,而是在vue文件里面书写效果代码,这样便于维护

1、在根目录下建一个skeleton文件夹,在该目录下创建文件App.vue文件(根组件,类似Vue项目的App.vue)、home.skeleton.vue(首页骨架屏展示效果的代码,类似Vue项目写的路由页面)、skeleton-entry.js(入口文件类似Vue项目的入口文件)、plugin/server-plugin.js(vue-server-renderer包提供了server-plugin插件,从里面将代码拷贝出来)

home.skeleton.vue(首页骨架屏展示效果的代码)

<template><div class="skeleton-home"><div>加载中...</div></div>
</template><style>
.skeleton-home {width: 100vw;height: 100vh;background-color: #eaeaea;
}
</style>

App.vue(根组件)

<template><div id="app"><!-- 根组件 --><home style="display:none" id="homeSkeleton"></home></div>
</template>
<script>
import home from './home.skeleton.vue'
export default{components: {home}
}
</script>
<style>
#app {font-family: 'Avenir', Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;
}
*{padding: 0;margin: 0;
}
</style>

skeleton-entry.js(入口文件)

// 入口文件
import Vue from 'vue'
import App from './App.vue'
let skeleton = new Vue({render(h) {return h(App)}
})
export default skeleton

plugin/server-plugin.js(vue-server-renderer包提供了server-plugin插件)

'use strict';/*  */var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };var ref = require('chalk');
var red = ref.red;
var yellow = ref.yellow;var prefix = "[vue-server-renderer-webpack-plugin]";
var warn = exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); };
var tip = exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); };var validate = function (compiler) {if (compiler.options.target !== 'node') {warn('webpack config `target` should be "node".');}if (compiler.options.output && compiler.options.output.libraryTarget !== 'commonjs2') {warn('webpack config `output.libraryTarget` should be "commonjs2".');}if (!compiler.options.externals) {tip('It is recommended to externalize dependencies in the server build for ' +'better build performance.');}
};var VueSSRServerPlugin = function VueSSRServerPlugin (options) {if ( options === void 0 ) options = {};this.options = Object.assign({filename: 'vue-ssr-server-bundle.json'}, options);
};VueSSRServerPlugin.prototype.apply = function apply (compiler) {var this$1 = this;validate(compiler);compiler.plugin('emit', function (compilation, cb) {var stats = compilation.getStats().toJson();var entryName = Object.keys(stats.entrypoints)[0];var entryAssets = stats.entrypoints[entryName].assets.filter(isJS);if (entryAssets.length > 1) {throw new Error("Server-side bundle should have one single entry file. " +"Avoid using CommonsChunkPlugin in the server config.")}var entry = entryAssets[0];if (!entry || typeof entry !== 'string') {throw new Error(("Entry \"" + entryName + "\" not found. Did you specify the correct entry option?"))}var bundle = {entry: entry,files: {},maps: {}};stats.assets.forEach(function (asset) {if (asset.name.match(/\.js$/)) {bundle.files[asset.name] = compilation.assets[asset.name].source();} else if (asset.name.match(/\.js\.map$/)) {bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[asset.name].source());}// do not emit anything else for serverdelete compilation.assets[asset.name];});var json = JSON.stringify(bundle, null, 2);var filename = this$1.options.filename;compilation.assets[filename] = {source: function () { return json; },size: function () { return json.length; }};cb();});
};module.exports = VueSSRServerPlugin;

2、新建一个骨架屏构建配置文件:build/webpack.skeleton.conf.js,这个文件配合vue-server-renderer插件,将App.vue内容构建成单个json格式的文件

'use strict'const path = require('path')
const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('../skeleton/plugin/server-plugin')module.exports = {// 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import),// 并且还会在编译 Vue 组件时,// 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。target: 'node',// 对 bundle renderer 提供 source map 支持devtool: 'source-map',// 将 entry 指向应用程序的 server entry 文件entry: path.resolve(__dirname, '../skeleton/skeleton-entry.js'),output: {path: path.resolve(__dirname, '../skeleton'),  // 生成的文件的目录publicPath: '/skeleton/',filename: '[name].js',libraryTarget: 'commonjs2' // 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)},module: {rules: [{test: /\.vue$/,loader: 'vue-loader',options: {compilerOptions: {preserveWhitespace: false}}},{test: /\.css$/,use: ['vue-style-loader', 'css-loader']}]},performance: {hints: false},// https://webpack.js.org/configuration/externals/#function// https://github.com/liady/webpack-node-externals// 外置化应用程序依赖模块。可以使服务器构建速度更快,// 并生成较小的 bundle 文件。externals: nodeExternals({// 不要外置化 webpack 需要处理的依赖模块。// 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件,// 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单allowlist: /\.css$/}),// 这是将服务器的整个输出// 构建为单个 JSON 文件的插件。// 不配置filename,则默认文件名为 `vue-ssr-server-bundle.json`plugins: [new VueSSRServerPlugin({filename: 'skeleton.json'})]
}

3、使用webpack-cli运行文件webpack.skeleton.conf.js,生成skeleton.json文件,放置在文件夹skeleton下

在package.json文件里面书写运行命令:create-skeleton

  "scripts": {"create-skeleton": "webpack --progress --config build/webpack.skeleton.conf.js","fill-skeleton": "node ./skeleton/skeleton.js"}

在控制台上运行命令:

npm run create-skeleton

文件夹skeleton下就会多出skelleton.json文件

4、将生成的skeleton.json内容注入到根目录下的index.html(模版文件)

1)在文件夹skeleton下新建skeleton.js

// 将生成的skeleton.json的内容填充到模板文件中
const fs = require('fs')
const { resolve } = require('path')
const createBundleRenderer = require('vue-server-renderer').createBundleRenderer// 读取skeleton.json,以skeleton/index.html为模版写入内容
const renderer = createBundleRenderer(resolve(__dirname, '../skeleton/skeleton.json'), {template: fs.readFileSync(resolve(__dirname, '../skeleton/index.html'), 'utf-8')
})
// 把上一步模版完成的内容写入根目录下的模版文件'index.html'
renderer.renderToString({}, (err, html) => {if (err) {return console.log(err)}console.log('render complete!')fs.writeFileSync('index.html', html, 'utf-8')
})

2)添加运行命令:fill-skeleton

"fill-skeleton": "node ./skeleton/skeleton.js"

3)在控制台上运行该命令,则skeleton.json文件内容被填充至根目录下的模板文件index.html了

参考文章:

利用Vue SSR 做骨架屏注入:https://www.cnblogs.com/goloving/p/11397371.html

在Vue中实现骨架屏:http://www.360doc.com/content/20/0709/11/21412_923150401.shtml

Vue ssr渲染踩过的坑:https://blog.csdn.net/chen801090/article/details/105974987/

在vue项目中使用骨架屏相关推荐

  1. Vue项目中添加锁屏功能

    0. 直接上 预览链接 Vue项目中添加锁屏功能 1. 实现思路 ( 1 ) 设置锁屏密码 ( 2 ) 密码存localStorage (本项目已经封装h5的sessionStorage和localS ...

  2. vue项目中实现录屏两种方式rrweb和RecordRTC

    rrweb原理 rrweb 是一个实现web页面录制和回放的基础库 ,它可以将⻚⾯中的 DOM 以及⽤户操作保存为可序列化的数据,以实现远程回放. RecordRTC原理 1.rrweb 安装npm ...

  3. Vue中实现骨架屏的多种方式

    vue-cli项目首页加载缓慢想要使用骨架屏效果,经过几天的实践,这里学习并记录一下vue项目自动生成骨架屏方法.  前言:骨架屏的作用主要是在网络请求较慢时,提供基础占位,当数据加载完成,恢复数据展 ...

  4. 骨架屏技术讲解以及如何在Vue中实现骨架屏

    骨架屏技术讲解以及如何在Vue中实现骨架屏 写在前面 骨架屏是什么 如何实现(原理分析) 一个生动的例子 实现方式(具体实现) 方案一.在模版中来实现骨架屏 方案二.使用一个Base64的图片来作为骨 ...

  5. Vue 项目中各种痛点问题及方案

    作者:愣锤 原文:https://juejin.im/post/6844903632815521799 最近要求使用vue进行前后端分离开发微信公众号,不断摸索踩坑之后,总结出如下几点vue项目开发中 ...

  6. methods vue过滤器 和_数据动态过滤技巧在 Vue 项目中的实践

    这个问题是在下在做一个 Vue 项目中遇到的实际场景,这里记录一下我遇到问题之后的思考和最后怎么解决的(老年程序员记性不好 -.-),过程中会涉及到一些Vue源码的概念比如 $mount. rende ...

  7. 在vue项目中引用萤石云播放器插件

    在vue项目中引用萤石云播放器插件 1. 萤石云官方开发文档: https://open.ys7.com/help/31 2. 登录官方网站:https://open.ys7.com/cn/s/ind ...

  8. Vue项目中Echarts流向图迁徙图实现

    在数据可视化中,地图可视化是高频应用的一种.我们在一些新闻报道和商业杂志上,会经常看到运用地图来分析展示商业现象,这样的利用地图来反映和分析数据的形式叫数据地图.数据地图可以最直观的表达出数据之间的空 ...

  9. vue项目中的小知识--快捷键-vue插件版本号--vscode插件等

    vue项目中的小知识--快捷键等 0 版本号 1 代码片段的获取: 2 vscode中一些常用扩展 3 进入另一个文件夹,返回上一级 4查看Vue的版本和Vue/CLI的版本 5 --save-dev ...

  10. vue项目中导入视频

    vue项目中引入视频插件 一.安装插件 vue-video-player npm install vue-video-player -s 二.在main.js里倒入并使用 import VideoPl ...

最新文章

  1. 百度发的208亿春晚红包,靠这样的技术送到了你手上 | 解读
  2. 服务器越来越慢的原因及解决办法
  3. 【解决方案】Expected object of type torch.FloatTensor but found type torch.DoubleTensor
  4. Servlet,GenericServlet和HttpServlet的继承关系
  5. Fuxi ServiceModeJob 多租户(Quota Group) 功能介绍
  6. mysql 全文索引 权重_MySQL中的全文索引
  7. java文件下载用什么技术_Java中实现文件上传下载的三种解决方案(推荐)
  8. CUDA C编程权威指南 第五章 共享内存和常量内存
  9. Apache20、lighttpd、nginx的比较[zt]
  10. .net|dotnet应聘人员应该掌握的知识点
  11. [转]使用SCOM 2012监控网络
  12. SpringBoot解决驼峰命名 ---返回Json实体类属性大小写问题
  13. 用户故事与敏捷方法 - 第二章 编写故事
  14. web 网页设计规范介绍
  15. python爬虫的线程、进程、异步的基础讲解
  16. matlab randn state 2,matlab中randn(‘state’)
  17. 《茅屋为秋风所破歌》古诗鉴赏
  18. 2019长三角科技金融峰会召开 链塔CEO张翔分享区块链应用前景
  19. 学生管理系统【Python】
  20. plc通讯块FC5、FC6

热门文章

  1. 内网穿透服务器搭建教程,NPS使用教程
  2. CentOS下安装EDM工具
  3. [OpenGL] L系统 分形树的实现(L-System植物建模)
  4. 关于windows虚拟桌面使用及录屏
  5. 海湾gst5000协议号_海湾GST5000主机操作说明
  6. 过 DNF TP 驱动保护(二)
  7. linux下使用screen和ping命令对网络质量进行监控
  8. java小红球下载_小红球闯关下载_小红球闯关合集版下载-游戏下载
  9. 招聘-中软国际外派中国移动(广州)
  10. mysql dcn_Tdsql DCN同步技术原理介绍