给Vue集成Skeleton骨架屏,并加持PWA

给Vue集成Skeleton骨架屏,并加持PWA

背景

这几天刚了解了PWA,但是实际项目受限于基础环境(https)无法快速落地,找来Vue这个Demo项目,再整理一下,为后面实际落地做准备。

玩法

基于Vue-cli创建的项目,加入Skeleton和PWA属性,升级Demo项目

步骤

  1. 通过Vue-cli搭建Vue项目
  2. 加持PWA
  3. 加入Skeleton

步骤一:搭建Vue项目

通过Vue官网资源,通过Vue-cli搭建Vue项目说明应该还是很详细的,这里不在赘述。

注意需要手动安装“prettier”

npm install prettier@1.12.0

步骤二:加持PWA

Vue对自己的定义同样包含“渐进式”JavaScript框架,所以应该和PWA还是蛮般配的。

通过Google提供的PWA开发继承工具Workbox,可以快速给我们的应用加持PWA:

1. 安装依赖

# 项目添加workbox-webpack-plugin组件
npm install --save-dev workbox-webpack-plugin

# 项目添加sw-register-webpack-plugin组件
npm install --save-dev sw-register-webpack-plugin

2. 在webpack中引用插件,并设置配置信息

// webpack.dev.conf.js、webpack.prod.conf.js webpack配置文件添加插件配置
const WorkBoxPlugin = require('workbox-webpack-plugin')
const SwRegisterWebpackPlugin = require('sw-register-webpack-plugin')

// 以service-worker.js文件为模板,注入生成service-worker.js
new WorkBoxPlugin.InjectManifest({
    swSrc: path.resolve(__dirname, '../src/service-worker.js')
}),
// 通过插件注入生成sw注册脚本
new SwRegisterWebpackPlugin({
  version: +new Date()
}),

3. workbox(service-worker)配置,主要是局部缓存策略

// 启动后停止旧的sw
workbox.skipWaiting()
workbox.clientsClaim()

// 设置缓存名称前缀
workbox.core.setCacheNameDetails({
  prefix: 'vuecli'
})

// 缓存manifest.json
workbox.routing.registerRoute(
  /\/manifest\.json/,
  workbox.strategies.staleWhileRevalidate()
)

// sw-register网络请求优先
workbox.routing.registerRoute(
  /\/sw-register\.js/,
  workbox.strategies.networkOnly()
)

workbox.precaching.precacheAndRoute(self.__precacheManifest || [])

上面几步就完成了!信不信?就是这么easy!

workbox注册成功
注册成功后,offline后也可以正常访问哦~

步骤三:加入Skeleton

Skeleton,骨架屏,在页面数据尚未加载前先给用户展示出页面的大致结构,直到请求数据返回后再渲染页面,补充进需要显示的数据内容,一般用于首页、数据列表等。

我们可以通过vue-skeleton-webpack-plugin快速实现骨架屏的搭建

1. 安装vue-skeleton-webpack-plugin

npm install --save-dev vue-skeleton-webpack-plugin 

2. 添加Skeleton.vue骨架页面

<template>
   <div class="skeleton-wrapper">
        <header class="skeleton-header"></header>
        <section class="skeleton-block">
            <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg==">
            <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg==">
        </section>
    </div>
</template>

<script>
export default {
  name: 'skeleton'
}
</script>

<style scoped>
  .skeleton-header {
    height: 152px;
    background: grey;
    margin-top: 60px;
    width: 152px;
    margin: 60px auto;
  }

  .skeleton-block {
    display: flex;
    flex-direction: column;
    padding-top: 8px;
  }
</style>

3. 添加骨架屏入口entry-skeleton.js

import Vue from 'vue'
import Skeleton from './components/Skeleton'

export default new Vue({
  components: {
    Skeleton
  },
  template: '<skeleton />'
})

4. webpack中加入skeleton打包插件

new SkeletonWebpackPlugin({
  webpackConfig: require('./webpack.skeleton.conf')
})
加入Skeleton加载效果

参考文档:

示例代码:


追加一点修改:vue-skeleton-webpack-plugin支持多页面多骨架屏的配置,具体配置如下:

// webpack配置中
new SkeletonWebpackPlugin({
  webpackConfig: require('./webpack.skeleton.conf'),
  router: {
    mode: 'hash',
    routes: [
      {
        path: '/',
        skeletonId: 'skeleton'
      },
      {
        path: '/detail',
        skeletonId: 'skeleton_detail'
      }
    ]
   }
})

对应的页面就需要有多个骨架屏页面,只需要修改entry-skeleton文件即可:

export default new Vue({
  components: {
    Skeleton,
    SkeletonDetail
  },
  // 多骨架屏从实现上看,实际上是把多个骨架屏都加载到页面上
  // 然后通过webpackconfig中的routes配置的skeletonId确定显示某一个skeleton
  template: `
    <div>
      <skeleton id="skeleton" style="display:none"/>
      <skeletonDetail id="skeleton_detail" style="display:none"/>
    </div>
  `
})

编辑于 2018-05-31 13:32