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. UK Biobank专题

    这个时代的生信,统计遗传,不懂或不会用这个数据库就说不过去了. 看看10年GWAS里是如何定位和评价UK biobank的: For the near future, the UK Biobank i ...

  2. vue报错:There are multiple modules with names that only differ in casing.

    今天写项目时,遇到报错信息如下: 经过多次排除及参考网上文章,最后找到问题所在 排查原因:1 .在引用组件时,路径大小写不对也会造成此报错,看例子:错误写法: 正确写法: 2.在组件使用vuex时,引 ...

  3. Python 23种设计模式全(python例子)

    从今年5月份开始打算把设计模式都写到博客里,持续到现在总算是写完了.写的很慢,好歹算是有始有终.对这些设计模式有些理解的不准确,有些甚至可能是错的,请看到的同学拍砖留言.内容来源很杂,大部分参考或者摘 ...

  4. ImageSwitcher 图片切换器

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  5. oracle DBA 常用表和视图

    ☆dba_开头.....   dba_users      数据库用户信息   dba_segments  表段信息   dba_extents    数据区信息   dba_objects    数 ...

  6. 【439】Tweets processing by Python

        参数说明: coordinates:Represents the geographic location of this Tweet as reported by the user or cl ...

  7. 【438】Python 处理文件

    1. 读取文件,计算 tweets 数目 python中readline判断文件读取结束的方法 line == '' python:如何检查一行是否为空行 line == '\n' or line = ...

  8. spring 通过注解装配Bean

    使用注解的方式可以减少XML的配置,注解功能更为强大,它既能实现XML的功能,也提供了自动装配的功能,采用了自动装配后,程序员所需要做的决断就少了,更加有利于对程序的开发,这就是“约定优于配置”的开发 ...

  9. Python - Django - ORM F查询和Q查询

    models.py: from django.db import models # 出版社 class Publisher(models.Model): id = models.AutoField(p ...

  10. 从零开始封装React UI 组件库并发布到NPM

    github 开源地址:zswui github 说明文档:wiki 1.新建目录wui (1)进入到 wui 目录 执行 npm init 命令初始化项目.更具提示信息填充将会生成的 package ...