缓解弱网vue应用的白屏

677 阅读4分钟

选中重要内容后,点击悬浮工具栏中的“ ... ”然后选择“高亮块”,突出显示重点信息

为什么会出现白屏

在弱网环境下,初始化页面元素如下图

加载app.js需要需要一定的时间,就会造成页面白屏

下图就是等待加载app.js下白屏情况

应用入口处理

直接在public文件下的index.html文件里增加

  <div id="app">

      <div id="app-loading">

        <div class="loading-point loading-point-1"></div>

        <div class="loading-point loading-point-2"></div>

        <div class="loading-point loading-point-3"></div>

        <div class="loading-point loading-point-4"></div>

        <div class="loading-point loading-point-5"></div>

      </div>

    </div>
      #app-loading {

        width: 200px;

        height: 50px;

        position: fixed;

        left: 50%;

        top: 50%;

        transform: translate(-50%, -50%);

        visibility: hidden;

        /**

          组件实例300ms内未挂载将会显示动画, 而不是在页面请求开始就显示动画

        */

        animation: app-delay-loading 1s .6s infinite;

      }

      .loading-point {

        display: inline-block;

        width: 15px;

        height: 15px;

        border-radius: 15px;

        background-color: #4b9cdb

      }

  

      .loading-point-1 {

        animation: app-loading 2s infinite

      }

  

      .loading-point-2 {

        animation: app-loading 2s infinite;

        animation-delay: .15s

      }

  

      .loading-point-3 {

        animation: app-loading 2s infinite;

        animation-delay: .30s

      }

  

      .loading-point-4 {

        animation: app-loading 2s infinite;

        animation-delay: .45s

      }

  

      .loading-point-5 {

        animation: app-loading 2s infinite;

        animation-delay: .60s

      }

  

      @keyframes app-loading {

        0% {

          transform: translateY(0)

        }

  

        35% {

          transform: translateY(0);

          opacity: .3

        }

  

        50% {

          transform: translateY(-20px);

          opacity: .8

        }

  

        70% {

          transform: translateY(3px);

          opacity: .8

        }

  

        85% {

          transform: translateY(-3px)

        }

      }

  

      @keyframes app-delay-loading {

        0% {

          visibility: visible;

        }

  

        100% {

          visibility: visible;

        }

      }

效果如下

使用 webpack 插件 vue-skeleton-webpack-plugin

vue-skeleton-webpack-plugin 样式不能根据内容生成骨架屏,是一开始写的什么就是什么

效果如下:

vue-skeleton-webpack-plugin 参数说明

SkeletonWebpackPlugin

  • webpackConfig 必填,渲染 skeleton 的 webpack 配置对象
  • insertAfter 选填,渲染 DOM 结果插入位置,默认值为字符串 '<div id="app">'

    • 也可以传入 Function,方法签名为 insertAfter(entryKey: string): string,返回值为挂载点字符串
  • quiet 选填,在服务端渲染时是否需要输出信息到控制台
  • router 选填 SPA 下配置各个路由路径对应的 Skeleton

    • mode 选填 路由模式,两个有效值 history|hash
  • routes 选填 路由数组,其中每个路由对象包含两个属性:

    • path 路由路径 string|RegExp
  • skeletonId Skeleton DOM 的 id string
  • minimize 选填 SPA 下是否需要压缩注入 HTML 的 JS 代码

vue.config.js 配置如下

const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')

const path = require('path')

// vue.config.js

module.exports = {

    productionSourceMap: false, // 设置上线后是否加载webpack文件

    configureWebpack: config => {

        config.plugins.push(

            new SkeletonWebpackPlugin({

                webpackConfig: {

                    entry: {

                        app: path.join(__dirname, './src/Skeleton.js'), //这里为上面的entry-skeleton.js

                    },

                },

                minimize: true,

                quiet: true,

                router: {

                    mode: 'history',

                    routes: [

                        {

                            path: '/', //和router.js中的路径一样就行

                            skeletonId: 'listSkeleton', //之前的id

                        },

                        {

                            path: /^/about/,

                            skeletonId: 'detailSkeleton',

                        },

                    ],

                },

            })

        )





    },

    css: {

        extract: false,

    },

}

其中 skeleton.js 是我们骨架屏的入口,我们过会再创建。先看来一下其中 router 这个配置项。

router 的配置决定了我们各个路由路径所对应的骨架屏。

  • router.mode 填路由模式,两个值可选 history | hash.
  • router.routes 填路由数组,其中 path 对应着页面在 vue-router 中的 pathskeletonId 是骨架屏的 id,后面马上会说明。

skeleton.js

配置完成后,新建一个骨架屏的入口 skeleton.js。

import Vue from 'vue'

import listSkeleton from './skeleton/listSkeleton'

import detailSkeleton from './skeleton/detailSkeleton'

 

export default new Vue({

  components: {

    listSkeleton,

    detailSkeleton

  },

  template: `

    <div>

      <listSkeleton id="listSkeleton" style="display:none;" />

      <detailSkeleton id="detailSkeleton" style="display:none;" />

    </div>

  `

})

上面的代码中,引入的两个组件分别对应 首页(listSkeleton) 和 详情页(detailSkeleton) 的骨架屏,其中组件的 id 对应之前在 vue.config.jsskeletonId

listSkeleton 和 detailSkeleton 就是我们要展示的骨架屏页面,在ui输出效果图的时候同时输出骨架屏图,ui没有输出骨架图,我们又懒得写样式,可以用dps-master自动生成骨架屏

dps-master 自动生成骨架屏

使用方法:

  1. dps init 生成配置文件 dps.config.js
  2. 修改 dps.config.js 进行相关配置
  3. dps start 开始生成骨架屏

dps.config.js 配置说明如下

无法复制加载中的内容

const dpsConfig = {

  url: 'https://baidu.com',      // 待生成骨架屏页面的地址,用百度(https://baidu.com)试试也可以

  output: {

    filepath: '',   // 生成骨架屏的存放页面,一般为项目的入口页面

    injectSelector: '#app'  // 生成的骨架屏插入页面的节点

  },

  // header: {

  //  height: 40,

  //  background: '#3388ff'

  // },

  background: '#eee',

  animation: 'opacity 1s linear infinite;',

  // includeElement: function(node, draw) {

    // 定制某个节点画出来的样子,带上return false

    // if(node.id == 'ui-alert') {

      // 跳过该节点及其子节点

      // return false;

    // }

    // if(node.tagName.toLowerCase() === 'img') {

      // 对该图片生成宽100%,高8%,颜色为红色的色块

      // draw({

        // width: 100,

        // height: 8,

        // left: 0,

        // top: 0,

        // zIndex: 99999999,

        // background: 'red'

      // });

      // return false;

    // } 

  // },

  // writePageStructure: function(html) {

    // 自己处理生成的骨架屏

    // fs.writeFileSync(filepath, html);

    // console.log(html)

  // },

  init: function() {

    // document.querySelectorAll('.m-icon').forEach(item => item.parentNode.removeChild(item));

    // 生成骨架屏之前的操作,比如删除干扰节点

  }

}





module.exports = dpsConfig;

总结

无法复制加载中的内容