antd-mobile
Version:
<div align="center">
93 lines • 3.24 kB
JavaScript
import React, { useState, useRef, memo } from 'react';
import classNames from 'classnames';
import { CloseOutline, SoundOutline } from 'antd-mobile-icons';
import { useTimeout } from 'ahooks';
import { mergeProps } from '../../utils/with-default-props';
import { withNativeProps } from '../../utils/native-props';
import { useResizeEffect } from '../../utils/use-resize-effect';
import { useMutationEffect } from '../../utils/use-mutation-effect';
const classPrefix = `adm-notice-bar`;
const defaultProps = {
color: 'default',
delay: 2000,
speed: 50,
wrap: false,
icon: React.createElement(SoundOutline, null)
};
export const NoticeBar = memo(p => {
const props = mergeProps(defaultProps, p);
const containerRef = useRef(null);
const textRef = useRef(null);
const [visible, setVisible] = useState(true);
const speed = props.speed;
const delayLockRef = useRef(true);
const animatingRef = useRef(false);
function start() {
if (delayLockRef.current || props.wrap) return;
const container = containerRef.current;
const text = textRef.current;
if (!container || !text) return;
if (container.offsetWidth >= text.offsetWidth) {
animatingRef.current = false;
text.style.removeProperty('transition-duration');
text.style.removeProperty('transform');
return;
}
if (animatingRef.current) return;
const initial = !text.style.transform;
text.style.transitionDuration = '0s';
if (initial) {
text.style.transform = 'translateX(0)';
} else {
text.style.transform = `translateX(${container.offsetWidth}px)`;
}
const distance = initial ? text.offsetWidth : container.offsetWidth + text.offsetWidth;
animatingRef.current = true;
text.style.transitionDuration = `${Math.round(distance / speed)}s`;
text.style.transform = `translateX(-${text.offsetWidth}px)`;
}
useTimeout(() => {
delayLockRef.current = false;
start();
}, props.delay);
useResizeEffect(() => {
start();
}, containerRef);
useMutationEffect(() => {
start();
}, textRef, {
subtree: true,
childList: true,
characterData: true
});
if (!visible) return null;
return withNativeProps(props, React.createElement("div", {
className: classNames(classPrefix, `${classPrefix}-${props.color}`, {
[`${classPrefix}-wrap`]: props.wrap
}),
onClick: props.onClick
}, props.icon && React.createElement("span", {
className: `${classPrefix}-left`
}, props.icon), React.createElement("span", {
ref: containerRef,
className: `${classPrefix}-content`
}, React.createElement("span", {
onTransitionEnd: () => {
animatingRef.current = false;
start();
},
ref: textRef,
className: `${classPrefix}-content-inner`
}, props.content)), (props.closeable || props.extra) && React.createElement("span", {
className: `${classPrefix}-right`
}, props.extra, props.closeable && React.createElement("div", {
className: `${classPrefix}-close`,
onClick: () => {
var _a;
setVisible(false);
(_a = props.onClose) === null || _a === void 0 ? void 0 : _a.call(props);
}
}, React.createElement(CloseOutline, {
className: `${classPrefix}-close-icon`
})))));
});