一直都是用的第三方库的loading
组件(ant-design/antd-mobil
),最近一个项目需要用到loading,自己开发了下,总结如下:
Loading
组件的两种形式:全局loading
、局部loading
- 全局loading:一般覆盖全屏居中显示,这种情况的调用方式一般是编程式调用即
Loading.show()
-
局部loading:只对某个区块进行loading,这种情况一般是组件包裹形式使用
// 使用方式同 Spin 组件 <Spin visible={true}> <div>区块内容</div> </Spin>
- 两种情况都做了请求速度过快时的
防闪烁
处理
意外收获 portals
- 在开发全局loading时,再想怎么把loading组件挂在body顶层时,用了
ReactDom.render
这个方法一般是一些脚手架帮我们生成项目代码时自动生成的把顶层App组件放在root节点上时才会用到,这里我们利用它把 loading组件挂在我们指定的顶层dom节点上 -
ReactDOM.createPortal(child, container)
官方文档、 知乎学习文章portals这个东西就是可以把组件放到指定的dom节点,而使用时依旧可以像普通使用组件那样使用,只不过生成的dom树不是在一起的 官方话术:Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案 而且支持合成事件冒泡 利用这个方法开发一些 Dialog、Modal 组件就非常方便、非常简洁了 antd的 Modal 组件也是用的这个方法
两种loading代码如下
-
全局loading,这里用到了
ReactDom.render(<Comps/>, domNode)
这个顶层apiimport 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'); } }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。