What is a skeleton screen?

In simple terms, skeleton screen is not on the page render complete, with some simple graphics first roughly draw the outline of the basic outline of the page, to the user create the false impression that the page is loaded, after page rendering to finish with a page replace the skeleton screen, hang time, thus reducing the page to the user a better experience.

Analyze the VUE rendering process

Create a project with VUE-Cli3.0: vue create Project

<! 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>project</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but project 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>Copy the code

As you can see, there is a div#app in the DOM. When js is executed, the div#app will be replaced completely. Therefore, we have a clear idea of how to implement skeleton screen in the Vue page.

Implementation scheme

Writing skeleton screen content to div#app manually is unscientific and therefore requires a scalable, automated and easy maintenance solution. Since it is in a Vue project, the so-called skeleton screen is also a.vue file that can be automatically injected into div#app by tools at build time. First, we’ll create a new skeleton.vue file under the/SRC directory that looks like this:

<template>
  <div class="skeleton page">
    <div class="skeleton-nav"></div>
    <div class="skeleton-swiper">
        <div class="skeleton-swiper-item item-one"></div>
        <div class="skeleton-swiper-item item-two"></div>
    </div>
  </div>
</template>

<style>
html,body,div{
    margin:0;
    padding:0;
}
.skeleton {
  height: 100%;
  overflow: hidden;
  box-sizing: border-box;
  background: #fff;
}
.skeleton-nav {
  height: 54px;
  background: #eee;
  margin-bottom: 20px;
}
.skeleton-swiper {
    min-height:600px;
    max-width:1280px;
    margin:0 auto;
}
.skeleton-swiper-item{
    min-height: 600px;
    height:100%;
    background:#eee;
    border-radius:5px;
}
.item-one{
    width:20%;
    float:left;
}
.item-two{
    width:78%;
    float:right;
}
</style>
Copy the code

Next, create a new skeleton.entry.js entry file in/SRC:

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

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

With the skeleton screen ready, we need a key plug-in called vue-server-Renderer. The plugin is intended for server-side rendering, but here we will use its ability to process.vue files into HTML and CSS strings for skeleton screen injection.

Skeleton plate injection

Start by creating a new template. HTML file in the public folder with the same code as the index.html file, but add
placeholder:

<! 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="./favicon.ico"> <title> Doctor table </title> </head> <body> <noscript> <strong>We're sorry but yz_doctors doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"> <! --vue-ssr-outlet--></div> <! -- built files will be auto injected --> </body> </html>Copy the code

We then need to create a new webpack.skeleton.conf.js file in the root directory just for the skeleton screen build.

const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
    target: 'node',
    entry: {
        skeleton: './src/skeleton.entry.js',
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        publicPath: '/dist/',
        filename: '[name].js',
        libraryTarget: 'commonjs2',
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader'.'css-loader',]}, {test: /\.vue$/,
                loader: 'vue-loader',
            },
        ],
    },
    externals: nodeExternals({
        whitelist: /\.css$/,
    }),
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.esm.js',
        },
        extensions: [The '*'.'.js'.'.vue'.'.json'],
    },
    plugins: [
        new VueLoaderPlugin(),
        new VueSSRServerPlugin({
            filename: 'skeleton.json',})]};Copy the code

As you can see, this configuration file is basically the same as a common configuration file. The main differences are that the target is ‘node’, externals is configured, and VueSSRServerPlugin is added to plugins. In the VueSSRServerPlugin, you specify the JSON file name for its output. Then generate a skeleton.json file in the /dist directory by running the following command: Webpack — config. / webpack. Skeleton. Conf. Js next, in the root directory to create a new skeleton, js, the file will be used in the index. The inserting skeleton in HTML screen:

const fs = require('fs');
const { resolve } = require('path');
const htmlMinifier = require('html-minifier');
const createBundleRenderer = require('vue-server-renderer').createBundleRenderer; // Replace vue template file index. HTML with standard template to prevent skeleton screen contaminationlet tempData = fs.readFileSync(resolve(__dirname, './public/template.html'), 'utf-8');
fs.writeFileSync('./public/index.html', tempData, 'utf-8');
console.log('Template injection completed'); // Const renderer = createBundleRenderer(resolve(__dirname,'./dist/skeleton.json'), {
    template: fs.readFileSync(resolve(__dirname, './public/index.html'), 'utf-8')}); Renderer. RenderToString ({}, (err, HTML) => {if (err) {
        console.log(err);
        return;
    }
    html = htmlMinifier.minify(html, {
        collapseWhitespace: true,
        minifyCSS: true}); fs.writeFileSync('./public/index.html', html, 'utf-8');
});
console.log('Skeleton panel injection completed');

Copy the code

Next, just run Node skeleton.js to complete the skeleton screen injection. To automatically inject the skeleton screen while NPM runs serve and avoid running multiple commands, add the “preserve” command to package.json: “Webpack — config. / webpack. Skeleton. Conf., js && node skeleton. Js”, in the “serve” before.

conclusion

The purpose of creating the template. HTML file is to keep the template file clean, because every time the skeleton screen is injected, the
The placeholder has been replaced by the skeleton screen code, the skeleton screen can not be completed after the skeleton screen injection, so the template. Instead of manually modifying the index. HTML file every time you modify the skeleton screen, run a command to automatically inject the skeleton screen.