Notice.tsx文件:

import { BellOutlined, NotificationOutlined } from '@ant-design/icons';
import React, { useEffect, useState } from 'react'
import styles from './xxx.module.css';// css文件自行命名interface IProps {data: IObj;onClickNoticeDetail?:(item, index) => any;
}
interface IObj {noticeList: INoticeList[];animate: boolean;
}
interface INoticeList {key: number|string;text: string;detailText?: string|null;
}export const Notice = (props: IProps) => {const {onClickNoticeDetail, data} = props;let [obj, setObj] = useState<any>(data);//页面加载的时候,设置一个永恒的定时器,1.5s后就会执行定时器中的逻辑useEffect(()=>{setTimeout(() => {obj['animate'] = truechangeAnim()}, 2000);}, [obj])//在setInterval执行中,会调用该函数,在内部会设置一个一次性的定时器,每次都会将数组的第一个元素添加到数组的最后,并且将数组的第一个元素删除,const changeAnim = () => {const { noticeList } = objsetTimeout(() => {const noticeList1 = JSON.parse(JSON.stringify(noticeList))noticeList1.push(noticeList1[0]);noticeList1.shift();setObj({...obj,noticeList: noticeList1,animate: false})}, 1500)}const renderContent = () =>  {const { noticeList, animate } = obj;return (<div className={styles["scrollPage"]}><div className={styles["scrollWrapper"]}><ul className={animate ? styles['anim'] : ''}>{noticeList.map((item, index) => {return <li key={index}><span onClick={()=>{onClickNoticeDetail&&onClickNoticeDetail(item, index)}}><NotificationOutlined translate={undefined}/></span><span className="text">{item.text}</span>{/* <span><BellOutlined translate={undefined} /><i>222222</i></span> */}</li>})}</ul></div></div>)}return renderContent()
}

css文件:

.scrollPage {margin: 0px;z-index: 999999999999999999999;height: 100px;position: fixed;top: 0;.scrollWrapper {position: relative;height: 24px;line-height: 24px;overflow: hidden;}& ul {position: absolute;top: 20px;left: 0;height: 24px;overflow: hidden;left: 400px;box-sizing: border-box;}&  li {list-style: none;height: 24px;line-height: 24px;display: flex;width: 800px;}& li>span:first-child,& li>span:nth-child(3) {display: inline-block;font-size: 24px;}& li>span:nth-child(3) {position: relative;flex: 0 0 100px;}& li>span:nth-child(3)>i {display: inline-block;min-width: 20px;height: 14px;line-height: 12px;border-radius: 5px;position: absolute;left: 10px;font-size: 12px;color: #fff;}& li>span:nth-child(2) {display: inline-block;flex:1;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
}.anim {transition: all .5s;margin-top: 24px;
}

模拟数据及引用:

let obj1 = {noticeList: [{key: 1,text: '11iPhone11挥泪降价1600元 iPhone12出道即巅峰?5G手机11',detailText: '11'},{key: 2,text: '22R式体验奔驰博物馆重新开张 广东最惨的"88888"车牌VR式体验奔驰博物馆重新开张 VR式体验奔驰博物馆重新开张 广东最惨的"88888"车牌VR式体验奔驰博物馆重新开张 广东最惨的"88888"车牌22222222222222222222222222222222222222244444444444444444',detailText: '22'},{key: 3,text: '334年5队的落选秀太香了 巅峰2.6帽!力压魔兽夺最佳新秀33',detailText: '33'},{key: 4,text: '44你好世界:寻找心中的风景 [征集]寻找中式风景禅意美44',detailText: '44'},],animate: false,
}
<Notice data={obj1} onClickNoticeDetail={(item,index)=>{showMsgInfo(JSON.stringify(item));}}/>

如果需要点击通知图标时停止定时器:

引入文件--略interface IProps {data: IObj;onClickNoticeDetail?: (item, index, fn) => any;
}
interface IObj {noticeList: INoticeList[];animate: boolean;
}
interface INoticeList {key: number | string;text: string;detailText?: string | null;
}export const Notice = (props: IProps) => {const { onClickNoticeDetail, data } = props;let [obj, setObj] = useState<any>(data);let [timerList, setTimerList] = useState<any>([]);let [timer] = useState<any>(null);let [noticeFlagStorage] = useState<any>({cancelToken2: 'Y'});//页面加载的时候,设置一个永恒的定时器useEffect(() => {intervalStart();}, [obj])const intervalStart = () => {if (timer) {clearTimeout(timer);timer = null;}noticeFlagStorage.cancelToken2 = 'Y';timer = int1();timerList.push(timer);}const intervalEnd = () => {if (timer || timerList.length > 0) {console.log('=============结束了222222222==========');each(timerList, (item, index) => {clearTimeout(item);});setTimerList([]);clearTimeout(timer);timer = null;}}const int1 = () => {if ('cancelToken2' in noticeFlagStorage) {return setTimeout(() => {console.log('开始了2222-----', timerList.length)obj['animate'] = true;if (noticeFlagStorage.cancelToken2 === 'N') {intervalEnd();}else {changeAnim()}}, 2000);}else {intervalEnd();return null;}}//在定时器执行中,会调用该函数,在内部会设置一个一次性的定时器,每次都会将数组的第一个元素添加到数组的最后,并且将数组的第一个元素删除,const changeAnim = () => {setTimeout(() => {const { noticeList } = obj;noticeList.push(noticeList[0]);noticeList.shift();setObj({...obj,noticeList,animate: false})}, 0);}const renderContent = () =>  {const { noticeList, animate } = obj;return (<div className={styles["scrollPage"]}><div className={styles["scrollWrapper"]}><ul className={animate ? styles['anim'] : ''}>{noticeList.map((item, index) => {return <li key={index}><span onClick={()=>{noticeFlagStorage.cancelToken2 = 'N'onClickNoticeDetail&&onClickNoticeDetail(item, index, intervalStart)}}><NotificationOutlined translate={undefined}/></span><span className="text">{item.text}</span></li>})}</ul></div></div>)}return renderContent()
}

使用: 点击弹窗确认按钮继续定时器

<Notice data={obj1} onClickNoticeDetail={(item,index, intervalStart)=>{Modal.success({mask: false,okText: '确认',content: '公告内容',centered: true,onOk: () => {showMsgInfo(JSON.stringify(item));intervalStart()},});}}/>

但有的公告栏是只展示第一个, 循环跑马灯式播放:

css:

@keyframes wordsloop {0% {transform: translateX(0px);}100% {transform: translateX(-100%);}}
& li>p>span {height: 24px;line-height: 24px;background: rgba(0,0,0,0);border: 0;display: inline-block;flex:1;white-space: nowrap;width: auto;margin-left: 10px;font-size: 14px;color: #333;}

tsx文件:

// 根据公告内容的所在的标签的宽度与其父标签比较, 设置宽度; 传入动画时间比写在css中可控
useEffect(() => {if (get(ref1, 'children[0].scrollWidth') + 10 < ref1.clientWidth/2) {setStyle1({width: `${get(ref1, 'clientWidth')}px`,minWidth: `${get(ref1, 'clientWidth')}px`,animation: `${styles['wordsloop']} ${animationDuration}s linear infinite normal`,})}else {setStyle1({width: 'auto',minWidth: 'auto',animation: `${styles['wordsloop']} ${animationDuration}s linear infinite normal`,})}}, [ref1, animationDuration])// 公告栏标签部分代码,其他略...
<div className={styles["scrollPage"]}><div className={classNames(styles["scrollWrapper"], appear === 'solidBlue' ? styles.scrollWrapperBlue : '')}><ul>{noticeList.map((item, index) => {return <li key={index} onClick={() => {clickNotice(item, index, undefined);}}><span><i style={appear === 'solidBlue' ? {filter: 'drop-shadow(40px 0 0 #007aff)',transform: 'translateX(-40px)'} : {}}></i></span><p ref={ref => setRef1(ref)}><span style={style1}>{item.CONTENT}</span><span style={style1}>{item.CONTENT}</span></p ></li>})}</ul></div></div>

还有一个需要优化的地方: 当页面纵向滚动时因为position是fixed的缘故,一直停留在固定位置, 如果需要随着滚动平移到正确位置, 可以监听滚动事件解决:

const handleScroll = (event: any = {}) => {// 滚动的高度const scrollTop: number =(event?.srcElement ? event?.srcElement?.scrollTop : 0) ||window.pageYOffset ||(event?.srcElement ? event?.srcElement?.body?.scrollTop : 0) ||0if (scrollTop >= 0) {setStyle0({transform: `translateY(-${scrollTop}px)`})}}useEffect(() => {window.addEventListener('scroll', handleScroll, true); // 滚动事件}, [window]);// 公告栏标签
<div className={classNames(styles["scrollPage"], appear === 'solidRed' ? styles['scrollPageRed'] : '')} style={style0}><div className={classNames(styles["scrollWrapper"], appear === 'solidBlue' ? styles.scrollWrapperBlue : '')}><ul>{noticeList.map((item, index) => {return <li key={index} onClick={() => {clickNotice(item, index, undefined);}}><span><i style={appear === 'solidBlue' ? {filter: 'drop-shadow(40px 0 0 #007aff)',transform: 'translateX(-40px)'} : {}}></i></span><p ref={ref => setRef1(ref)}><span style={style1}>{item.CONTENT}</span><span style={style1}>{item.CONTENT}</span></p ></li>})}</ul></div></div>

react 公告栏组件+定时器写法优化相关推荐

  1. React类组件的两种写法

    react中类组件的两种写法: 要点:•类组件必须要继承React.Component •类组件中的render()方法,返回值是一个jsx // 方式一: import React from 're ...

  2. 深入学习React函数组件性能优化三剑客useMemo、useCallback、memo

    Hook使用规则 只能在函数的最外层调用Hook,不能在循环.条件判断或子函数中调用. 只能在React函数组件或自定义Hook中调用Hook,不可在其他JavaScript函数中使用. useMem ...

  3. React创建组件的三种方式及其区别

    React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归:具体的三种方式: 函数式定义的无状态组件 es5原生方式React.createClass定义的组件 es6形式的ext ...

  4. onclick=两个函数_[译]React函数组件和类组件的差异

    [译]React函数组件和类组件的差异 原文: https://overreacted.io/how-are-function-components-different-from-classes/ 在 ...

  5. 【React 基础】之 React 面向组件编程

    准备工作 使用 React 开发者工具调试 复习 类 相关知识 定义 class(类),代码如下: // 创建一个 Person 类 class Person {// 构造器方法constructor ...

  6. React 函数式组件缓存原理

    对 React 函数式组件缓存的思考 自从 React 16.8 版本推出 Hooks 用法以来,围绕函数组件的优化出现了各种不同的思考.本篇文章从 React 底层 Render 角度,分析 Rea ...

  7. 【React】1138- React Hooks 性能优化的正确姿势

    前言 React Hooks 出来很长一段时间了,相信有不少的朋友已经深度使用了.无论是 React 本身,还是其生态中,都在摸索着进步.鉴于我使用的 React 的经验,给大家分享一下.对于 Rea ...

  8. 第一章:Reac入门 与 第二章:React面向组件编程

    目录 一.jsx语法规则 二.React中定义组件 1.函数式组件: 2.类式组件:*有关类复习的知识点前往React知识铺垫查看https://blog.csdn.net/m0_61927991/a ...

  9. react 调用组件方法_React源码分析1 — 组件和对象的创建(createClass,createElement)...

    1 组件的创建 学习了半年前端了,感觉前端的水确实也很深.做安卓的时候就对React-Native比较感兴趣,开发H5时也使用了一段时间的ReactJS.所以决定好好分析下它的源码.文章中有不对的地方 ...

最新文章

  1. 美国芯片简史:军方大力扶持下的产物 但一度被日 韩超越
  2. 消灭Bug!推荐7款优秀的开源Bug跟踪工具
  3. java中字符串压缩成bcd码_Java 压缩 / 解压缩字符串
  4. 东南大学2004年程序设计第一届初赛解题报告
  5. (原) Data Blocks, Extents, and Segments
  6. 如何通过ActivationStart监控 Angular的路由激活事件
  7. python的pass语句_适用于pass语句的Python程序
  8. 大整数减法c语言_3.2 C语言运算符和表达式
  9. 披星戴月地辛苦割胶或成历史,海南胶园迎来这一“神器”!
  10. Redis Cluster部署、管理和测试
  11. iOS charles 抓包使用
  12. HBuilderX - 高效极客技巧
  13. 【论文阅读】SCRDet++
  14. 从 几 个应用入手 了解为什么灵魂绑定代币将为 DeFi 带来大规模采用
  15. 校招/社招/秋招/春招求职指南
  16. 使用echarts在地图中使用dispatchAction
  17. 如何提取abaqus的位移和其坐标
  18. av_interleaved_write_frame(fmt_ctx, enc_pkt);返回-22
  19. 嵌入式系统驱动高级【5】——input子系统
  20. CCF-CSP Python Cheat Sheet

热门文章

  1. 如今区块链在企业级应用中的尴尬, 只因没看懂这4大主链2大场景……
  2. js 判断昨天,前天,去年
  3. Centos7下关于memcached的安装和简单使用
  4. Mac OS使用技巧之七:个性化自己的Mac OS主界面
  5. CSS元素的显示与隐藏
  6. ABOV单片机外部引脚中断EINT实现讲解及示例代码-[MC96F6332D]
  7. 冰河世纪:AIOps的落地实践之路
  8. 几个超火的在线编程网站,别错过
  9. 在线订机票系统用例说明
  10. python长整数相乘_Python中的分数与整数相乘