import React, { useState, useEffect, useRef, FunctionComponent, useImperativeHandle, MouseEvent, CSSProperties, } from 'react' import './noticebar.scss' import { number } from 'prop-types' import Icon from '../icon' import bem from '@/utils/bem' import classNames from 'classnames' export interface NoticeBarProps { // 滚动方向 across 横向 vertical 纵向 direction: string className?: string style?: CSSProperties list: any standTime: number complexAm: boolean height: number text: string closeMode: boolean wrapable: boolean leftIcon: string color: string background: string delay: string | number scrollable: boolean speed: number rightIcon?: HTMLElement | any close?: (list?: any) => void click?: (item?: any) => void } const defaultProps = { // 滚动方向 across 横向 vertical 纵向 direction: 'across', list: [], standTime: 1000, complexAm: false, height: 40, text: '', closeMode: false, wrapable: false, leftIcon: '', color: '', background: '', delay: 1, scrollable: true, speed: 50, } as NoticeBarProps export const NoticeBar: FunctionComponent< Partial & React.HTMLAttributes > = (props) => { const { children, className, style, direction, list, standTime, complexAm, height, text, closeMode, wrapable, leftIcon, color, background, delay, scrollable, speed, rightIcon, close, click, } = { ...defaultProps, ...props } const wrap = useRef(null) const content = useRef(null) // const [scrollList,SetScrollList] = useState([]) const [showNoticeBar, SetShowNoticeBar] = useState(true) let scrollList: any = useRef([]) const [wrapWidth, SetWrapWidth] = useState(0) const [firstRound, SetFirstRound] = useState(true) const [duration, SetDuration] = useState(0) const [offsetWidth, SetOffsetW] = useState(0) const [animationClass, SetAnimationClass] = useState('') const [animate, SetAnimate] = useState(false) const [distance, SetDistance] = useState(0) const [timer, SetTimer] = useState(0) const [index, setIndex] = useState(0) useEffect(() => { if (direction == 'vertical') { if (children) { let arr: any = [] React.Children.map(children, (child) => { arr.push((child as any).props.children) }) // SetScrollList([].concat(arr)) scrollList.current = [].concat(arr) } else { // SetScrollList([].concat(list)) scrollList.current = [].concat(list) } setTimeout(() => { complexAm ? startRoll() : startRollEasy() }, Number(standTime)) } else { initScrollWrap(text) } return () => { clearInterval(timer) } }, []) const cloneChild = (listItem: any, listIndex: any) => { return React.Children.map(children, function (child: any, index) { if (child && index == listIndex) { return React.cloneElement(child, { key: listIndex, children: listItem, }) } }) } useEffect(() => { initScrollWrap(text) }, [text]) useEffect(() => { if (list && list.length) { scrollList.current = [].concat(list) } }, [list]) const initScrollWrap = (value: string) => { if (showNoticeBar == false) { return } setTimeout(() => { if (!wrap.current || !content.current) { return } const wrapW = wrap.current.getBoundingClientRect().width const offsetW = content.current.getBoundingClientRect().width if (scrollable && offsetW > wrapW) { SetWrapWidth(wrapW) SetOffsetW(offsetW) SetDuration(offsetW / speed) SetAnimationClass('play') } else { SetAnimationClass('') } }) } const handleClick = (event: MouseEvent) => { click && click(event) } const onClickIcon = (event: MouseEvent) => { event.stopPropagation() SetShowNoticeBar(!closeMode) close && close(event) } const onAnimationEnd = () => { SetFirstRound(false) setTimeout(() => { SetDuration((offsetWidth + wrapWidth) / speed) SetAnimationClass('play-infinite') }, 0) } /** * 利益点滚动方式一 */ const startRollEasy = () => { showhorseLamp() let timerCurr = window.setInterval( showhorseLamp, ~~(height / speed / 4) * 1000 + Number(standTime) ) SetTimer(timerCurr) } const showhorseLamp = () => { SetAnimate(true) setTimeout(() => { scrollList.current.push(scrollList.current[0]) scrollList.current.shift() SetAnimate(false) }, ~~(height / speed / 4) * 1000) } const startRoll = () => { let timerCurr = setInterval(() => { let chunk = 100 for (let i = 0; i < chunk; i++) { scroll(i, i < chunk - 1 ? false : true) } }, Number(standTime) + 100 * speed) SetTimer(timerCurr) } const scroll = (n: number, last: boolean) => { SetAnimate(true) setTimeout(() => { let long = distance long -= height / 100 SetDistance(long) if (last) { scrollList.current.push(scrollList.current[0]) scrollList.current.shift() SetDistance(0) SetAnimate(false) } }, n * speed) } /** * 点击滚动单元 */ const go = (item: any) => { click && click(item) } const handleClickIcon = () => { close && close(scrollList[0]) } const iconShow = () => { if (leftIcon == 'close') { return false } else { return true } } const contentStyle = { paddingLeft: firstRound ? 0 : wrapWidth + 'px', animationDelay: (firstRound ? props.delay : 0) + 's', animationDuration: duration + 's', } const barStyle = { color: color, background: background, height: direction == 'vertical' ? `${height}px` : '', } const horseLampStyle = { transform: complexAm ? `translateY(${distance}px)` : '', transition: animate ? `all ${~~(height / speed / 4)}s` : '', marginTop: animate ? `-${height}px` : '', } const b = bem('noticebar') const noticebarClass = classNames({ 'nut-noticebar-page': true, withicon: closeMode, close: closeMode, wrapable: wrapable, }) return (
{showNoticeBar && direction == 'across' ? (
{!leftIcon ? : null}
{children} {text}
{closeMode ? (
) : null}
) : scrollList.current.length > 0 && direction == 'vertical' ? (
{children ? (
  {scrollList.current.map((item: any, index: any) => { return cloneChild(item, index) })}
) : (
    {scrollList.current.map((item: any, index: any) => { return (
  • { go(item) }} > {item}
  • ) })}
)}
{ handleClickIcon() }} > {rightIcon ? ( rightIcon ) : closeMode ? ( ) : null}
) : null}
) } NoticeBar.defaultProps = defaultProps NoticeBar.displayName = 'NutNoticeBar'