组件名称:系统公告
描述:悬浮的公告栏,作用于一条消息,长度不定,公告栏宽度自适应屏幕
代码场景: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;
}