一直都是用的第三方庫的loading
組件(ant-design/antd-mobil
),最近一個項目須要用到loading,本身開發了下,總結以下:
Loading
組件的兩種形式:全局loading
、局部loading
Loading.show()
局部loading:只對某個區塊進行loading,這種狀況通常是組件包裹形式使用html
// 使用方式同 Spin 組件 <Spin visible={true}> <div>區塊內容</div> </Spin>
防閃爍
處理portals
ReactDom.render
這個方法通常是一些腳手架幫咱們生成項目代碼時自動生成的把頂層App組件放在root節點上時纔會用到,這裏咱們利用它把 loading組件掛在咱們指定的頂層dom節點上ReactDOM.createPortal(child, container)
官方文檔、 知乎學習文章node
portals這個東西就是能夠把組件放到指定的dom節點,而使用時依舊能夠像普通使用組件那樣使用,只不過生成的dom樹不是在一塊兒的 官方話術:Portal 提供了一種將子節點渲染到存在於父組件之外的 DOM 節點的優秀的方案 並且支持合成事件冒泡 利用這個方法開發一些 Dialog、Modal 組件就很是方便、很是簡潔了 antd的 Modal 組件也是用的這個方法
全局loading,這裏用到了 ReactDom.render(<Comps/>, domNode)
這個頂層apireact
import React from 'react'; import ReactDOM from 'react-dom'; import './style/loading'; class Loading { domNode: HTMLElement isExistNode: boolean timer: any constructor() { this.domNode = document.createElement('div'); this.isExistNode = false; } private render(visible: boolean) { if (!this.isExistNode && visible) { document.body.appendChild(this.domNode); const children = this.createNode(); ReactDOM.render(children, this.domNode); this.isExistNode = true } if (visible) { this.domNode.className = 'hp-loading-wrap'; } else { this.domNode.className = 'hp-loading-wrap hide'; // ReactDOM.unmountComponentAtNode(this.domNode) } } createNode() { const node = <div className="loading-content"><div className="loading-img"></div></div>; return node; } show(isDelay=true, delay=300) { this.timer && clearTimeout(this.timer) if (!isDelay) { this.render(true); } else { // 防閃爍 this.timer = setTimeout(() => this.render(true), delay); } } hide() { this.timer && clearTimeout(this.timer) this.render(false) } } export default new Loading() // 樣式 .hp-loading-wrap { position: fixed; z-index: 99999; width: 100%; height: 100%; top: 0; left: 0; display: flex; align-items: center; &.hide { display: none; } .loading-content { width: 37.5px;/*no*/ height: 18px;/*no*/ margin: 0 auto; text-align: center; } .loading-img { width: 100%; height: 100%; margin: 0 auto; background-repeat: no-repeat; background-size: contain; background-position: center; background-image: url(../image/loading.gif) } }
局部loading,這裏用了hooks
,使用方式同 antd Spin
組件編程
import React, { useState, useEffect } from "react"; import './style/spin.less' interface propsType { visible: boolean; children?: any; tips?: any; delay?: number; } let timer:any; export default function Spin(props: propsType) { const [visible, setVisible] = useState(props.visible); useEffect(() => { if (props.delay) { // 防閃爍 timer && clearTimeout(timer); if (props.visible) { timer = setTimeout(() => setVisible(true), props.delay); } else { setVisible(false); } } else { setVisible(props.visible); } }, [props.visible]); return ( <div className={visible ? "hp-spin" : "hp-spin hide"}> {props.children} <div className={props.children ? "spin-content" : ''}> <div className="spin-img"></div> </div> </div> ); } // 樣式 .hp-spin { position: relative; .spin-content { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 999; } &.hide .spin-content { display: none; } .spin-img { display: inline-block; width: 37.5px;/*no*/ height: 18px;/*no*/ background-repeat: no-repeat; background-size: contain; background-image: url('../image/loading.gif'); } }