react 公告栏组件+定时器写法优化
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 公告栏组件+定时器写法优化相关推荐
- React类组件的两种写法
react中类组件的两种写法: 要点:•类组件必须要继承React.Component •类组件中的render()方法,返回值是一个jsx // 方式一: import React from 're ...
- 深入学习React函数组件性能优化三剑客useMemo、useCallback、memo
Hook使用规则 只能在函数的最外层调用Hook,不能在循环.条件判断或子函数中调用. 只能在React函数组件或自定义Hook中调用Hook,不可在其他JavaScript函数中使用. useMem ...
- React创建组件的三种方式及其区别
React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归:具体的三种方式: 函数式定义的无状态组件 es5原生方式React.createClass定义的组件 es6形式的ext ...
- onclick=两个函数_[译]React函数组件和类组件的差异
[译]React函数组件和类组件的差异 原文: https://overreacted.io/how-are-function-components-different-from-classes/ 在 ...
- 【React 基础】之 React 面向组件编程
准备工作 使用 React 开发者工具调试 复习 类 相关知识 定义 class(类),代码如下: // 创建一个 Person 类 class Person {// 构造器方法constructor ...
- React 函数式组件缓存原理
对 React 函数式组件缓存的思考 自从 React 16.8 版本推出 Hooks 用法以来,围绕函数组件的优化出现了各种不同的思考.本篇文章从 React 底层 Render 角度,分析 Rea ...
- 【React】1138- React Hooks 性能优化的正确姿势
前言 React Hooks 出来很长一段时间了,相信有不少的朋友已经深度使用了.无论是 React 本身,还是其生态中,都在摸索着进步.鉴于我使用的 React 的经验,给大家分享一下.对于 Rea ...
- 第一章:Reac入门 与 第二章:React面向组件编程
目录 一.jsx语法规则 二.React中定义组件 1.函数式组件: 2.类式组件:*有关类复习的知识点前往React知识铺垫查看https://blog.csdn.net/m0_61927991/a ...
- react 调用组件方法_React源码分析1 — 组件和对象的创建(createClass,createElement)...
1 组件的创建 学习了半年前端了,感觉前端的水确实也很深.做安卓的时候就对React-Native比较感兴趣,开发H5时也使用了一段时间的ReactJS.所以决定好好分析下它的源码.文章中有不对的地方 ...
最新文章
- 美国芯片简史:军方大力扶持下的产物 但一度被日 韩超越
- 消灭Bug!推荐7款优秀的开源Bug跟踪工具
- java中字符串压缩成bcd码_Java 压缩 / 解压缩字符串
- 东南大学2004年程序设计第一届初赛解题报告
- (原) Data Blocks, Extents, and Segments
- 如何通过ActivationStart监控 Angular的路由激活事件
- python的pass语句_适用于pass语句的Python程序
- 大整数减法c语言_3.2 C语言运算符和表达式
- 披星戴月地辛苦割胶或成历史,海南胶园迎来这一“神器”!
- Redis Cluster部署、管理和测试
- iOS charles 抓包使用
- HBuilderX - 高效极客技巧
- 【论文阅读】SCRDet++
- 从 几 个应用入手 了解为什么灵魂绑定代币将为 DeFi 带来大规模采用
- 校招/社招/秋招/春招求职指南
- 使用echarts在地图中使用dispatchAction
- 如何提取abaqus的位移和其坐标
- av_interleaved_write_frame(fmt_ctx, enc_pkt);返回-22
- 嵌入式系统驱动高级【5】——input子系统
- CCF-CSP Python Cheat Sheet