import React from 'react'
import PropTypes from 'prop-types' import AnimationOperateFeedbackInfo from '../AnimationOperateFeedbackInfo'
import OperateFeedbackInfo from '../OperateFeedbackInfo' import './index.less' const OPERATE_ARRAY_MAX_LENGTH = 5 export default function AssistantOperateFeedbackArea({
processingOperateList, failedOperateList, onClickCleanFailedOperateBtn, animationEndCallback,
}) {
const operateWrapStyle = {
width: '200px',
height: '28px',
color: '#fff',
} return (
<div className="assistant-operate-feedback-area-wrap">
{
processingOperateList.length > 0 && (
<div
className="operate-feedback-area"
style={{
// queueMaxLength + 1 省略区域高度
height: `${processingOperateList.length > OPERATE_ARRAY_MAX_LENGTH ? (OPERATE_ARRAY_MAX_LENGTH + 1) * 28 : processingOperateList.length * 28}px`,
}}
>
{
processingOperateList.slice(0, OPERATE_ARRAY_MAX_LENGTH).map((item) => {
return (
<AnimationOperateFeedbackInfo
operateId={item.operateId}
operate={item.operate}
operateType={item.state}
animationEndCallback={animationEndCallback}
style={operateWrapStyle}
key={item.operateId}
/>
)
})
}
{
processingOperateList.length > OPERATE_ARRAY_MAX_LENGTH && (
<div
style={operateWrapStyle}
className="ellipsis-operate-info"
>
... ...
</div>
)
}
</div>
)
}
{
failedOperateList.length > 0 && (
<div
className="operate-feedback-area"
style={{
// queueMaxLength + 1 省略区域高度
height: `${failedOperateList.length > OPERATE_ARRAY_MAX_LENGTH ? (OPERATE_ARRAY_MAX_LENGTH + 1) * 28 : failedOperateList.length * 28}px`,
}}
>
{
failedOperateList.slice(0, OPERATE_ARRAY_MAX_LENGTH).map((item) => {
return (
<div className="operate-feedback-info-wrap">
<OperateFeedbackInfo
operate={item.operate}
style={operateWrapStyle}
iconRotate={false}
iconPath={require('~/shared/assets/image/red-white-warn-icon-60-60.png')}
/>
</div>
)
})
}
<div
className="clean-failed-feedback-info-btn"
onClick={onClickCleanFailedOperateBtn}
tabIndex={0}
role="button"
>
清除所有异常
</div>
{
failedOperateList.length > OPERATE_ARRAY_MAX_LENGTH && (
<div
style={operateWrapStyle}
className="ellipsis-operate-info"
>
... ...
</div>
)
}
</div>
)
}
{
processingOperateList.length === 0 && failedOperateList.length === 0 && (
<div className="no-feedback-info-tip">
暂无对教师端操作
</div>
)
}
</div>
)
} AssistantOperateFeedbackArea.propTypes = {
processingOperateList: PropTypes.array,
failedOperateList: PropTypes.array,
onClickCleanFailedOperateBtn: PropTypes.func,
animationEndCallback: PropTypes.func,
} AssistantOperateFeedbackArea.defaultProps = {
processingOperateList: [],
failedOperateList: [],
animationEndCallback: () => {},
onClickCleanFailedOperateBtn: () => {},
}
import React, { useRef, useLayoutEffect } from 'react'
import PropTypes from 'prop-types'
import CX from 'classnames' import './index.less' export default function OperateFeedbackInfo({
operate, iconPath, style, iconRotate, resetAnimation,
}) {
const imgRef = useRef(null) useLayoutEffect(() => {
if (resetAnimation === true) {
const imgElem = imgRef.current
imgElem.className = '' // 触发一次重绘 同步所有旋转的icon动画
imgElem.height = imgElem.offsetHeight imgElem.className = 'operate-icon-rotate'
}
}) return (
<div
className="operate-feedback-Info"
style={style}
>
<div className="operate-feedback-content">{operate}</div>
<div className="operate-feedback-state-icon">
<img
className={CX({
'operate-icon-rotate': iconRotate,
})}
src={iconPath}
alt=""
ref={imgRef}
/>
</div>
</div>
)
} OperateFeedbackInfo.propTypes = {
operate: PropTypes.string.isRequired,
iconPath: PropTypes.string.isRequired,
iconRotate: PropTypes.bool,
resetAnimation: PropTypes.bool,
style: PropTypes.object,
}
OperateFeedbackInfo.defaultProps = {
style: {},
resetAnimation: false,
iconRotate: false,
}
import React from 'react'
import PropTypes from 'prop-types' import CX from 'classnames'
import OperateFeedbackInfo from '../OperateFeedbackInfo' import './index.less' export default function AnimationOperateFeedbackInfo({
operateId, operate, operateType, animationEndCallback, style,
}) {
return (
<div
className={CX({
'animation-operate-feedback-info-wrap': true,
'animation-operate-feedback-processing-state': operateType === 'processing',
'animation-operate-feedback-success-state': operateType === 'success',
})}
onAnimationEnd={() => {
if (operateType === 'success') {
animationEndCallback(operateId)
}
}}
>
<OperateFeedbackInfo
resetAnimation={operateType !== 'success'}
operate={operate}
style={style}
iconRotate={operateType !== 'success'}
iconPath={operateType === 'success' ? require('~/shared/assets/image/icon-success-green-white-100-100.png') : require('~/shared/assets/image/processing-icon.svg')}
/>
</div>
)
} AnimationOperateFeedbackInfo.propTypes = {
operateId: PropTypes.string,
operate: PropTypes.string,
operateType: PropTypes.string,
animationEndCallback: PropTypes.func,
style: PropTypes.object,
} AnimationOperateFeedbackInfo.defaultProps = {
operateId: '',
operate: '',
operateType: '',
animationEndCallback: () => {},
style: {},
}

以上是所有UI部分(包括交互):效果如下:

下面是hoc逻辑部分:

import React, { Component } from 'react'
import {
observable,
action,
} from 'mobx'
import {
observer,
} from 'mobx-react' import uid from 'uuid' import { AssistantOperateFeedbackArea } from '@dby-h5-clients/pc-1vn-components'
import { Rnd } from 'react-rnd'
import _ from 'lodash' const operateListClump = observable.object({
failedOperateList: [],
processingOperateList: [],
}) class OperateState {
@action
constructor(operate = '') {
this.operateId = uid()
this.operate = operate
operateListClump.processingOperateList.push({ operate, operateId: this.operateId, state: 'processing' })
} operateId operate @action
success(operate = '') {
const operateIndex = _.findIndex(operateListClump.processingOperateList, { operateId: this.operateId })
operateListClump.processingOperateList[operateIndex] = { operate: operate || this.operate, operateId: this.operateId, state: 'success' }
} @action
failed(operate = '') {
operateListClump.failedOperateList.push({ operate: operate || this.operate, operateId: this.operateId, state: 'failed' })
_.remove(operateListClump.processingOperateList, { operateId: this.operateId })
}
} @observer
class AssistantOperateList extends Component {
static addOperate = action((operate) => {
return new OperateState(operate)
}) @action
removeSuccessOperate = (operateId) => {
_.remove(operateListClump.processingOperateList, { operateId })
} @action
handleCleanAllFailedFeedbackInfo = () => {
operateListClump.failedOperateList = []
} render() {
return (
<Rnd
bounds=".main-space-wrap"
dragHandleClassName="assistant-operate-feedback-area-wrap"
lockAspectRatio={16 / 9}
enableResizing={{
top: false,
right: false,
bottom: false,
left: false,
topRight: false,
bottomRight: false,
bottomLeft: false,
topLeft: false,
}}
default={{
x: 30,
y: 30,
}}
>
<AssistantOperateFeedbackArea
failedOperateList={operateListClump.failedOperateList.toJSON()}
processingOperateList={operateListClump.processingOperateList.toJSON()}
animationEndCallback={this.removeSuccessOperate}
onClickCleanFailedOperateBtn={this.handleCleanAllFailedFeedbackInfo}
/>
</Rnd>
)
}
} export default AssistantOperateList

使用说明:

在其它组件中导入:

import AssistantOperateList from '../AssistantOperateList'
const msg = AssistantOperateList.addOperate('协助开启答题器')
msg.success()
msg.failed()

react 提示消息队列 (支持动态添加,删除,多实例化)的更多相关文章

  1. easyui 扩展layout的方法,支持动态添加删除块

    $.extend($.fn.layout.methods, { remove: function(jq, region){ return jq.each(function(){ var panel = ...

  2. Lua中如何实现类似gdb的断点调试—09支持动态添加和删除断点

    前面已经支持了几种不同的方式添加断点,但是必须事先在代码中添加断点,在使用上不是那么灵活方便.本文将支持动态增删断点,只需要开一开始引入调试库即可,后续可以在调试过程中动态的添加和删除断点.事不宜迟, ...

  3. 编辑 Ext 表格(一)——— 动态添加删除行列

    一.动态增删行 在 ext 表格中,动态添加行主要和表格绑定的 store 有关, 通过对 store 数据集进行添加或删除,就能实现表格行的动态添加删除.   (1) 动态添加表格的行  gridS ...

  4. 用Javascript动态添加删除HTML元素实例 (转载)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. js实现网页收藏功能,动态添加删除网址

    <html> <head> <title> 动态添加删除网址 </title> <meta charset="utf-8"&g ...

  6. jquery动态添加删除div--事件绑定,对象克隆

    我想做一个可以动态添加删除div的功能.中间遇到一个问题,最后在manong123.com开发文摘 版主的热心帮助下解答了(答案在最后) 使用到的jquery方法和思想就是:事件的绑定和销毁(unbi ...

  7. jQuery动态添加删除CSS样式

    jQuery框架提供了两个CSS样式操作方法,一个是追加样式addClass,一个是移除样式removeClass,下面通过一个小例子讲解用法. jQuery动态追加移除CSS样式 <!DOCT ...

  8. JS动态添加删除html

    本功能要求是页面传一个List 集合给后台而且页面可以动态添加删除html代码需求如下: 下面是jsp页面代码 <%@ page language="java" pageEn ...

  9. C#控制IIS动态添加删除网站

    我的目的是在Winform程序里面,可以直接启动一个HTTP服务端,给下游客户连接使用. 查找相关技术,有两种方法: 1.使用C#动态添加网站应用到IIS中,借用IIS的管理能力来提供HTTP接口.本 ...

随机推荐

  1. IM 简介

    LayIM - 打造属于你自己的网页聊天系统http://layim.layui.com/ 瓜子IM智能客服系统的数据架构设计(整理自现场演讲) - 知乎https://zhuanlan.zhihu. ...

  2. Mac OS 安装 MySQL5.7

    在 macOS 上安装 MySQL 5.7 安装 Homebrew $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubuserconten ...

  3. PostgreSQL 登录时在命令行中输入密码

    有时候需要设置定时任务直接执行 sql 语句,但是 postgresql 默认需要人工输入密码,以下命令可以直接在命令行中直接填入密码 PGPASSWORD=pass1234 psql -U MyUs ...

  4. [原][bigemap][globalmapper]通过bigemap下载全球30米DEM高程数据(手动下载)(下载全球高精度dom卫片、影像、等高线、矢量路网、POI、行政边界)

    本文研究了bigemap下载高程数据的方式,但是严重不推荐使用这总手动方式,bigemap这个软件一次只能下载100M以内的高程数据,即使花钱,也不给你提供批量下载dem的方式!也有些其他更好的软件, ...

  5. 16个python常用魔法函数

    ==,is的使用 ·is是比较两个引用是否指向了同一个对象(引用比较). ·==是比较两个对象是否相等 1.__ init__(): 所有类的超类object,有一个默认包含pass的__ init ...

  6. Selenium踩坑记之iFrame的定位与切换

    转自:https://www.jianshu.com/p/6e7d0359e4bb Selenium是浏览器自动化测试的工具之一,用过的人都懂他的好,也被他坑的不要不要的.今天就聊聊Selenium的 ...

  7. 十一、LoadRunner组成和工作原理

    一.LoadRunner组成 虚拟用户发生器:Vuser Generator 压力调度和监控中心:Controller 压力生产器:Load Generator 压力结果分析工具:Analysis

  8. Dart中的数据类型转换:

    int -> string age.toString() string -> int int.parse('100'); String -> double 1 var onePoin ...

  9. EasyNVR是怎么做到Web浏览器播放RTSP摄像机直播视频延时控制在一秒内的

    背景说明 由于互联网的飞速发展,传统安防摄像头的视频监控直播与互联网直播相结合也是大势所趋.传统安防的直播大多在一个局域网内,在播放的客户端上也是有所限制,一般都是都需要OCX Web插件进行直播.对 ...

  10. 【linux学习笔记五】帮助命令

    man //查看ls作用 man ls man -f命令 相当于 whatis命令 --help ls --help help help shell help cd info详细命令帮助