react中实现系统公告-左右循环滚动(首尾衔接)

本文介绍了一个基于React和Hooks实现的系统公告组件,它能根据屏幕宽度自适应并支持滚动显示公告内容。组件特点包括内容滚动、首尾衔接模式及简单的状态管理。适合用于动态展示消息,且避免了外部插件的使用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

组件名称:系统公告
描述:悬浮的公告栏,作用于一条消息,长度不定,公告栏宽度自适应屏幕
代码场景:react,hooks,tsx,less
功能介绍:
1.内容根据宽度自适应,无法显示完整将自动滚动,如果满足显示则居中不动
2.左右滚动,首尾衔接模式滚动,(尾部只有可视化区域一半,首部将衔接从右边显示)
注:初品,未做过多的封装功能与扩展功能,个人喜好一般自己有能力写出来的组件尽量不用插件,长远角度对维护项目/自己都有好处,有好的优化或者不明白的在下方评论留言

index.tsx

/*
 * @Author: 刘强
 * @Date: 2022-02-08 10:18:06
 * @LastEditTime: 2022-02-08 15:11:58
 * @LastEditors: 刘强
 * @Description: 公告
 * 这是注释!
 */

import React, { useState, useEffect } from 'react';
import './index.less';

let tagTimer: any = null; //元素初始化计时器
let tagConutStatic: number = 0; //初始化执行统计
let scrollTimer: any = null; //滚动计时器
let moveNumberStatic: number = 0;
let maxMoveStatic: number = 0;
let maxViewStatic: number = 0;
let ceshi = '本平台目前提供的通道带积分本平台目前提供的通道带积分,';

const Notice = () => {
	const [visible, setVisible] = useState<boolean>(true); //公告显示
	const [isScroll, setIsScroll] = useState<boolean>(false); //是否滚动-控制预留
	const [moveNumber, setMoveNumber] = useState<number>(0); // 当前滚动距离
	const [maxMove, setMaxMove] = useState<number>(0); // 最大滚动距离
	const [maxView, setMaxView] = useState<number>(0); // 最大可视距离
	const [context, setContext] = useState<String>(''); //公告内容
	const [list, setList] = useState<Array<String>>([]); //公告内容
	const [tagConut, setTagConut] = useState<number>(0); //初始化执行统计

	// api 获取公告内容-后期接入服务端的接口就行了
	function getNoticeApi() {
		setContext(ceshi);
		setList([ceshi]);
		tagTimer = setInterval(() => {
			tagConutStatic++;
			setTagConut(tagConutStatic);
		}, 300);
	}
	// 计算是否需要滚动
	function checkScrollFn() {
		try {
			let dom = document.getElementsByClassName('notice-scroll')[0];
			if (!dom || dom.clientWidth === 0) return;

			let maxWidth =
				document.getElementsByClassName('notice-context')[0]
					.clientWidth;
			let newWidth = dom.clientWidth;
			setIsScroll(newWidth > maxWidth);
			setMaxMove(newWidth);
			setMaxView(maxWidth);
			clearInterval(scrollTimer);

			if (newWidth > maxWidth && list.length < 2) {
				noticeScrollFn();
				setList([context, context]);
			} else {
				clearInterval(scrollTimer);
				scrollTimer = null;
			}
			clearInterval(tagTimer);
			tagTimer = null;
		} catch (error) {
			console.log(error);
		}
	}
	// 滚动公告
	function noticeScrollFn() {
		scrollTimer = setInterval(() => {
			if (-moveNumberStatic > maxMoveStatic) {
				setMoveNumber(maxViewStatic / 2 - 3);

				// dom.push()
			} else {
				setMoveNumber(moveNumberStatic - 3);
			}
		}, 150);
	}
	// 渲染公告列表
	function renderList() {
		return list.map((item, index) => {
			return (
				<span
					key={index}
					style={{
						transform: `translateX(${
							moveNumber + (maxView / 2) * index
						}px)`,
					}}
					className="notice-scroll"
				>
					{item}
				</span>
			);
		});
	}

	//初始化公告
	useEffect(() => {
		getNoticeApi();
	}, []);
	// 公告接收开始计算
	useEffect(() => {
		checkScrollFn();
	}, [tagConut]);
	useEffect(() => {
		moveNumberStatic = moveNumber;
	}, [moveNumber]);
	useEffect(() => {
		maxMoveStatic = maxMove;
	}, [maxMove]);
	useEffect(() => {
		maxViewStatic = maxView;
	}, [maxView]);
	return (
		<div id="notice" className={`${visible ? '' : 'notice-hidden'}`}>
			<div
				className={`notice-context ${
					isScroll ? '' : 'notice-noscroll'
				}`}
			>
				{renderList()}
			</div>
			<span
				onClick={() => {
					setVisible(false);
				}}
				className="iconfont iconclose"
			></span>
		</div>
	);
};

export default Notice;

index.less

#notice {
    position: fixed;
    top: 70px;
    width: 100vw;
    height: 40px;
    box-sizing: border-box;
    padding: 0 20px 0 50px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    background-color: @disabled;
    z-index: 1000;
    .notice {
        &-context {
            color: #000;
            font-size: 14px;
            width: calc(100% - 30px);
            text-align: center;
            overflow: hidden;
            display: flex;
        }
        &-scroll {
            display: inline-block;
            white-space: nowrap;
            transition: all 0.3;
        }
        &-noscroll {
            justify-content: center;
        }
    }
    .iconclose {
        cursor: pointer;
        font-size: 14px;
        color: @white-close; //关闭颜色
        &:hover {
            color: @white-hover; //关闭颜色
        }
    }
}
.notice-hidden {
    display: none !important;
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值