路由跳轉前的骨架屏實現

1、前言

(注意:本文是針對路由懶加載的項目)css

(1)骨架屏相信大多數人都聽講過,也實現過。(還不清楚骨架屏是什麼的能夠參考 開發一個簡單易懂的webpack骨架屏插件html

但通常狀況下都是給首頁第一次加載的時候添加骨架屏,而不是給每一個路由頁面都加上骨架屏。vue

怎麼說呢?webpack

單頁面應用第一次加載的時候須要加載大量的js,css資源,若是網絡慢的狀況,首次打開頁面可能會出現十幾秒的白屏時間。 如今市場上都是針對首次加載作了骨架屏優化,不多有作路由跳轉到其餘頁面的骨架屏優化。(可能不少人都認爲不必作其餘路由頁面的骨架屏優化,但本文先忽略這個必要性)web

(2)看了vue-skeleton-webpack-plugin的源碼,發現該插件的routers也作不了其餘路由頁面的骨架屏優化。因此想出了本文的方案。vue-router

2、實現原理

(1)路由懶加載

市場上的單頁面應用多數都會作路由懶加載,以vue項目爲例: 在註冊vue-router的時候,通常像下圖作路由分割bash

大概意思就是,當跳轉到 /home 頁面的時候才加載/home頁面對應的js資源。只有當這個js資源加載完成以後頁面纔會更新。因此若是加載這個js資源的時間用了10幾秒,那麼咱們將會原地等待10幾秒,或者會白屏10幾秒。這樣的用戶體驗是很是很差的。網絡

若是咱們能夠在這10幾秒裏作一個骨架屏讓它先展現出來,等到js資源加載回來後再隱藏它。這樣的用戶體驗不是更加好呢。app

(2)實現原理:

如上圖,component對應的value是一個函數,該函數就是加載js資源的Promise, 衆所周知,Promise有then方法能夠知道js資源何時加載完成。那麼咱們能夠在import('../views/home/index.vue')以前先讓骨架屏顯示出來,讓<div id="app"></div>隱藏。而後在import('../views/home/index.vue').then()方法裏再將骨架屏隱藏,<div id="app"></div>顯示。svg

(2.1)首先對index.html作修改,以下:

在index.html裏添加兩個同級得div,一個是骨架屏得div,一個是<div id="app"></div>,你能夠在骨架屏得div裏寫上本身的樣式。再在<head>裏寫上簡單的顯示隱藏的css樣式

<!DOCTYPE html>
<html lang="en">
  <head>    
    <meta charset="UTF-8">    
    <meta name="viewport" content="width=device-width, initial-scale=1.0">    
    <meta http-equiv="X-UA-Compatible" content="ie=edge">    
    <title>Document</title>
    <style>
      .skeleton-block[data-v-07e00dc6] {  
        display: flex;  
        flex-direction: column;  
        padding: 16px;
      }
      .body-wrap-show .skeleton-wrap {
        display: block !important;
      }
      .body-wrap-show #app {
        display: none !important;
      }
      .body-wrap-hidden .skeleton-wrap {
        display: none !important;
      }
      .body-wrap-hidden #app {
        display: block !important;
      }
    </style>
  </head>
  <body>    
    <div data-server-rendered="true" class="skeleton-wrap" style="display: none;">
      <div data-v-07e00dc6>
        <section class="skeleton-block" data-v-07e00dc6>
          <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg==" data-v-07e00dc6> 
          <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg==" data-v-07e00dc6>
        </section>
      </div>
    </div>
    <div id="app"></div>    
    </script>
    </body>
    </html

複製代碼

(2.2)路由註冊文件的修改,以下

大概意思是:每次路由跳轉以前先將<div id="app"></div>隱藏,讓骨架怕展現。在then方法裏再讓<div id="app"></div>展現,骨架屏隱藏。這樣每次路由跳轉都會出現骨架屏了。

import Vue from 'vue';
import vueRouter from 'vue-router';
Vue.use(vueRouter);

const router = new vueRouter({
  mode: 'history',
  routes: [
    {
      path: '/home',
      component: () => {
        let body = document.body;
        // 每次路由跳轉以前先將<div id="app"></div>隱藏
        document.getElementById('app').style.display = 'none';
        // 移除body上的body-wrap-hidden
        body.classList.remove('body-wrap-hidden');
        // 在body上的添加class 爲body-wrap-show
        body.classList.add('body-wrap-show');

        return import('../views/home/index.vue').then(res => {
            //當js資源加載完成後,將骨架屏隱藏
            body.classList.remove('body-wrap-show');
            //當js資源加載完成後,將<div id="app"></div>展現
            body.classList.add('body-wrap-hidden');
            //釋放body節點的引用
            body = null;
            // 注意:then方法裏面必須得返回一個值,否則vue-router會報錯
            return res;
        })
      }
    },
  ]
});

export default router;

複製代碼

(2.4)效果以下:

留意上圖,當我點擊「我是首頁」的時候,是馬上出現骨架屏的,再看右邊的js資源是正在加載,尚未加載完成。也就是說,它不是使用v-if或者v-show在「我是詳情頁面」的頁面裏面作的骨架屏。後者它有個限制,由於後者所謂的骨架屏也是屬於「我是詳情頁面」的代碼,必須等待js資源返回後纔會顯示。而前者則是加載js資源以前就已經顯示了。 **

(2.3)結束語:

本文只是個思路,真正想作到每一個路由頁面都有各自的骨架屏還得作不少的事情。 (有不當之處還望指出)。

相關文章
相關標籤/搜索