共计 4298 个字符,预计需要花费 11 分钟才能阅读完成。
Vue 利用加载过程
咱们先来看看 vue 的入口文件 index.html 外面的内容,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
从图里看到 vue 页面从关上到加载实现是有一段 白屏 的工夫的,那 白屏 的加载体验对于首次拜访的用户来说是难以承受的,咱们能够应用尺寸稳固的骨架屏,来辅助实现实在模块占位和霎时加载。
vue 利用从关上到页面展现残缺大抵经验了一下几步
1. 先渲染 index.html 的内容
2. 动静插入 chunk-vendors.js(第三方库)
3. 动静插入 app.js(业务代码)
4. 渲染路由对应的页面
只有当 app.js 文件渲染实现之后,以后路由对应的 vue 才会被渲染到页面外面,而 app.js 是最初才被插入到 index.html 里的,因而会导致在 app.js 未加载之前会有一段空白的显示。
这会引出了一个用户体验的问题:用户看到页面内容之前的空白工夫过长,这样页面流失率会大大的减少,这也是咱们不违心看到的。
据统计:加载超过 5 秒就会有 74% 的用户来到页面。
骨架屏是什么
在页面齐全渲染实现之前,用户会看到一个款式简略,描述了以后页面的大抵框架,感知到页面正在逐渐加载,最终骨架屏中各个占位局部被齐全替换,体验良好。罕用于文章列表、动静列表页等绝对比拟规定的列表页面。
很多我的项目中都有利用: 饿了么 h5 版本, 知乎,facebook 等网站中都有利用。
这个过程中用户会感觉内容正在逐步加载行将出现,升高了用户的烦躁情绪,使得加载过程主观上变得晦涩。
骨架屏相比于传统的 loading 图会在感官上感觉内容呈现的晦涩而不突兀,体验更加低劣。
所以骨架屏的利用大大提高了用户体验。
上面咱们看看具体的实现办法
骨架屏实际
从 vue 渲染过程动图中咱们能看到 index.html 是最快加载的进去的
所以骨架屏须要放到 index.html 外面
在 index.html 将骨架屏 Dom 构造写好,而后在规定好的钩子函数外面去移除这个骨架屏就能够实现骨架屏机制。
然而这种形式有一个问题,如果每个页面的骨架屏的款式都不同,咱们须要手动在 index.html 写好每个页面对应的构造款式,而后再去解析路由去显示对应的骨架屏。这样很麻烦,不好保护。
呢有没有一个插件帮咱们去干两件事件:
1. 将骨架屏 vue 文件提前渲染到 index.html 外面
2. 渲染路由对应的骨架屏
这样一来就大大解放了双手,代码维护性也大大提高了。
vue-skeleton-webpack-plugin
github 地址:https://github.com/lavas-proj…
这是一个基于 Vue 的 webpack 插件,为单页 / 多页利用生成骨架屏 skeleton,缩小白屏工夫,在页面齐全渲染之前晋升用户感知体验。
将骨架屏也看成路由组件,在构建时应用 Vue 服务端渲染性能,将骨架屏组件的渲染后果 HTML 片段插入 HTML 页面模版的挂载点中,将款式内联到 head 标签中。这样等前端渲染实现时,Vue 将应用客户端混合,把挂载点中的骨架屏内容替换成真正的页面内容。
-
插件大抵实现思路
- 通过 vue-server-renderer 将骨架屏的 Vue 实例渲染为 HTML
- Vue webpack 我的项目应用了 HTML Webpack Plugin 生成 HTML 文件,通过该插件的 html-webpack-plugin-before-html-processing 事件的回调函数插入骨架屏的内容。
插件具体实现可参考作者文章
- 实现步骤
- 新建一个骨架屏的 vue 文件并将骨架屏的款式写好
- 在 src 文件加下新建一个 skeleton.js 文件,将方才创立的骨架屏文件引入,注册在 components 外面,并在 template 外面写入这个组件,留神:这里的组件肯定要申明 ID 值
import Vue from 'vue'
import SkeletonIndex from './components/skeleton/index'
export default new Vue({
components: {SkeletonIndex},
template: `
<div>
<SkeletonIndex id="skeletonIndex" style="display:none" />
</div>
`
})
3. 因为我的我的项目是 vue-cli3,所以要对 vue.config.js 操作, 这里须要引入 skeleton.js,并且能够在 routes 外面配置路由对应的骨架屏组件。留神 extract: true 必须要配置,否则骨架屏 vue 里的款式不会被插入到 style 外面。~~~~ 其余配置项能够到作者 github 上查问。
const path = require('path');
const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin');
module.exports = {
css: {extract: true},
configureWebpack: {
plugins: [
new SkeletonWebpackPlugin({
webpackConfig: {
entry: {app: path.join(__dirname, './src/skeleton.js'),
},
},
router: {
mode: process.env.NODE_ENV === 'development' ? 'hash' : 'history',
routes: [{ path: /.+/, skeletonId: 'skeletonIndex'},
]
}
}),
],
},
};
配置实现重启利用看一下成果
理论利用遇到的问题
因为这个插件应用的服务端渲染,所以当 app.$mount 挂载胜利后,骨架屏的内容会被替换掉。
当咱们的业务代码缓缓变多后,页面 dom 的绘制会变慢,所以会呈现骨架屏隐没后会有 短暂白屏 的状况。
解决方案:
因为我发现在 app.vue 外面注册的全局组件会比 <router-view></router-view> 里的提前渲染,所以我在 app.vue 外面注册一个骨架屏的全局变量,而后在 router.beforeEach 外面去依据路由动静渲染对应的骨架屏。
// app.vue
<template>
<div id="app">
<router-view></router-view>
<Skeleton />
</div>
</template>
<script>
import Skeleton from './components/app/skeleton/index'
export default {
components: {Skeleton}
}
</script>
// ./components/app/skeleton/index.vue
<template>
<div v-if="skeletonName" class="skeleton-wrapper">
<component :is="skeletonName"></component>
</div>
</template>
<script>
import {mapState} from 'vuex'
import allTop from './allTop'
import bless_sort from './bless_sort'
import classify_singer from './classify_singer'
import home from './home'
import loading from './loading'
import mv from './mv'
import photo from './photo'
import photov2 from './photov2'
import send_video from './send_video'
export default {
computed: {
...mapState({skeletonName: state => state.skeletonName})
},
components: {
allTop,
bless_sort,
classify_singer,
home,
loading,
mv,
photo,
photov2,
send_video
}
}
</script>
// main.js
router.beforeEach((to, from, next) => {store.commit('SAVE_TOGGLE_SKELETON', false)
if (util.skeletonCheckRoute(to.path)) {store.commit('SAVE_TOGGLE_SKELETON', util.skeletonCheckRoute(to.path, 'getPath'))
}
next()}
这样就解决了短暂白屏的问题,如果有更好的办法能够提出来。
总结
单利用的一个最大的问题就是首屏加载货色太多,加载工夫过长。
而骨架屏的利用只是升高了用户焦虑,咱们还是要优化代码体积。
- 按需加载
- 异步组件
- webpack-bundle-analyzer
- …
绘制骨架屏插件
vue-content-loader
在线绘制骨架屏网站:https://skeletonreact.com/
Vue Content Loader 是一个基于 Vue.js 的 SVG 占位符加载,可自定义的 SVG 组件,用于创立占位符加载,例如 Facebook 加载卡。
Vue Content Loader 是 react-content-loader 的 Vue 实现。