在頁面加載前新增 loading 狀態的幾種方式
loading 加載分為好幾種,一種是含百分比計算的,一種是不含百分比。
含百分比的需要進行計算,有的網站是通過定義不同的節點來進行計算,比如執行了一個 ajax 結束算一個節點,進度條增加百分之三十,再執行完一個再加百分之三十。這個方法我自己也沒有去實際做過,只是查資料了解到的,所以本文對此不作介紹。
不含百分比的就比較簡單,只需要放一個動畫就可以。
先記錄一下基本步驟
- 將 loading 頁和主頁面分開加載,因為所有的文件在主頁面都打包成了一個 js 文件,所以單獨將 loading 拿出來加載,處理方式是修改 webpack 打包文件
entry: {
main: './main/index.js', // 原本的主頁面文件
loading: './loading/index.js', // 新增的 loading 頁面文件
},
- 在 index.html 文件中,引入 loading.js 文件,引入的文件一定要放在 main.js 之前,因為要讓瀏覽器先加載 loading 文件
<body>
<main id="application-container"></main> <!--在 main.js 之前引入 loading.js 文件-->
<script src="/demo/static/apps/entry/loading.js"></script>
<script src="/demo/static/apps/entry/main.js"></script>
</body>
- 編輯 loading.js 文件內容,這才是重點的地方
我們的想法是先加載 loading 的動畫,當檢測到 dom 已經加載完畢以后,移除掉 loading 動畫,加載主頁面
此處需要下載 document-ready 庫用于檢測 document.ready 事件。
import ready from 'document-ready';
const loader = document.createElement('div');
const body = document.getElementsByTagName('body')[0]
const progress = '<div>正在加載啦啦啦啦</div>'; // loading 頁內容
loader.innerHTML = progress; body.appendChild(loader)
// 上面的內容基本就是在做一件事,就是創建新元素插入到 body 中
ready(() => {
// 當 document.ready 時,移除元素
body.removeChild(loader)
})
基本的步驟就是上述部分,但是很多時候我們并不希望只是一個簡陋的元素展示出來,希望有加載條或者一些動畫等等。下面分三種情況說明一下。
loading 動畫
動圖
直接使用 gif 其實是最簡單的部分,用 gif 替代普通的元素即可,如
const progress =<div>正在加載啦啦啦啦</div>
;
再加一些樣式即可,其實如果 dom 元素太多的話,可以另用一個文件去專門寫布局和樣式,然后再導入到 loading.js 中。-
含百分比加載條,現成的輪子:pace.js,可以直接下載 pace.js 以及它的主題,然后在 html 中引入,官網上寫得很清楚了。另外一種方式是 npm 下載了,這里有兩個地方要注意。
- 下載的包名并不是 pace,而是 pace-js,yarn add pace-js 下載的才是正確的包
- 引入 pace 模塊的時候有 bug,無法直接通過 import pace from 'pace-js' 引入 pace module,原因是 pace.js 中的 AMD define 時出錯了,它將 pace 定義為依賴,但是 pace 在 npm 中是另外的一個不關聯 CLI 進度條包的庫,也就是說和這個庫沒有什么關系,具體解決方法:
在 webpack 中新增下面這條語句
{
test: require.resolve("pace-progress"),
loader: "imports?define=>false"
}
下載 imports-loader 包:yarn add imports-loader,然后就解決了。
原因和解決方法都是參考這個 issue:[我是解決問題的 issue](https://github.com/HubSpot/pace/issues/328)
解決這些以后,就可以直接使用 pace 了,但是一定要記得進入 pace 的樣式包,當然也可以自己寫,根據以下的 class 寫自己指定的樣式,也可以直接使用 pace 文檔中已有的樣式。
<div class="pace pace-inactive">
<div class="pace-progress" data-progress-text="100%" data-progress="99" style="transform: translate3d(17%, 0px, 0px);">
<div class="pace-progress-inner" style=" background: black;">
</div>
</div>
<div class="pace-activity"></div>
</div>
pace.start() 開始加載進度條,pace.stop() 則停止加載,它沒有 done 方法,凡事可以監聽 done 事件,在加載執行完成時觸發的事件,方法如下:
pace.on("done",function(){
console.log('im done!');
})
使用中遇到的問題:使用 pace 的過程中發現一個問題,pace 執行 stop() 時貌似是異步的,如果將 pace.stop() 放入 ready(){} 中執行,loading 頁面的加載條還未結束,或者結束還未消失,主頁面已經出現,導致加載條覆蓋住了主頁面。所以也許 pace 的用法是需要增加一個 mask 遮罩層或者僅僅用在 ajax 上比較合理?(雖然不僅僅能用在 ajax 上)。
- 使用 nprogress
nprogress 類似于 pace,但是沒有出現 pace 出現的上述多個問題,而且它沒有自帶主題,貌似只有一個固有樣式,但是我們仍然可以對它進行自定義。
用法如下:
yarn add nprogress
引入 Nprogress 模塊,也要記得引入樣式
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
在需要的地方執行 Nprogress.start() 開始加載進度條,在任何需要的地方執行 Nprogress.done() 結束進度條,展示出來的效果就是它的默認樣式了。
我們可以對它的樣式進行自定義,或者干脆對它的DOM元素進行自定義,它原本的結構如下:
<div id="nprogress">
<div class="bar" role="bar" style="transform: translate3d(-73.2731%, 0px, 0px); transition: all 200ms ease;">
<div class="peg"></div>
</div>
<div class="spinner" role="spinner">
<div class="spinner-icon"></div>
</div>
</div>
通過以上結構是默認結構,我們可以自己寫一份 css,然后引入到 loading/index.js 文件當中。
或者可以通過以下方式自定義結構,
const progress = `<div id="nprogress">
<div class="bar" role="bar" style="background: red; transform: translate3d(-0.6%, 0px, 0px); transition: all 200ms ease;">
<div class="peg" style="box-shadow: 0 0 10px #fff, 0 0 5px #fff;"></div>
</div>
<div class="spinner" role="spinner">
<div class="spinner-icon" style="border-top-color:white;border-left-color: white"></div>
</div>
</div>`;
NProgress.configure({ template: progress, });
這只是一個例子,progress 的內容可以單獨作為一個文件,再 import 進來,需要注意幾個地方:
configure 顧名思義是對 Nprogress 進行設置,所以要放在 Nprogress.start() 之前。
在自定義結構時,要給一些元素指定role屬性,這個是必須要指定的,不然 nprogress 不清楚哪個元素該做什么。比如:
role="bar" //表示的是加載條
role="spinner" //表示的是原本樣式中右上角的旋轉,具體叫什么我也說不上來...
在本處,我們就通過如下方式來進行:
// loading/index.js
import NProgress from 'nprogress'; // 引入 Nprogress 模塊
import progress from './demo/index'; // 自定義的 dom
NProgress.configure({
// 設置自己定義的dom
template: progress,});
NProgress.start(); // 加載進度條
ready(() => {
NProgress.done(); // 結束并移除進度條
})
progress 同樣遇到 pace 一樣的問題,即 loading 內容還沒消失,主頁面內容就已經顯示了,document.ready 的節點執行 nprogress.done() 的操作,首先滾動條到滾動到達最底的位置,然后再讓 loading 消失,這幾個步驟需要一定的時間,所以會出現這種情況。pace 剛才的問題應該同樣是這個原因。只能讓 template 盡量簡潔,減少渲染時間。
我個人更傾向于用 nprogress。如果喜歡 pace 的主題又想用 progress 的,可以直接去參考樣式,內容并不多,畢竟兩者的 dom 結構比較相似,樣式名換一下再稍微修改修改應該就能用起來。
當然如果想要更多自己定制的內容,還是需要去看 pace 或者 progress 官網,鏈接如下:
pace
progress