antd-mobile-taro-ui
Version:
以antd-mobile为设计标准,基于taro框架的微信小程序组件库
119 lines (112 loc) • 4 kB
JavaScript
import React, { useState, useRef, memo, useEffect, useMemo } from 'react';
import classNames from 'classnames';
import { CloseIcon, NotificationIcon } from 'antd-mobile-taro-icons';
import { useTimeout } from 'ahooks';
import { mergeProps } from 'antd-mobile/es/utils/with-default-props';
import { withNativeProps } from 'antd-mobile/es/utils/native-props';
import { useResizeEffect } from 'antd-mobile/es/utils/use-resize-effect';
import { useMutationEffect } from 'antd-mobile/es/utils/use-mutation-effect';
import { View } from '@tarojs/components';
import Taro from '@tarojs/taro';
import { uuid } from '../../utils/uuid';
const classPrefix = `adm-notice-bar`;
const defaultProps = {
color: 'default',
delay: 2000,
speed: 50,
icon: React.createElement(NotificationIcon, 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;
const [containerRefWidth, setContainerRefWidth] = useState(0);
const [textRefWidth, setTextRefWidth] = useState(0);
const containerRefId = useMemo(() => `${classPrefix}-content-${uuid()}`, []);
const textRefId = useMemo(() => `${classPrefix}-content-inner-${uuid()}`, []);
const delayLockRef = useRef(true);
const animatingRef = useRef(false);
function start() {
if (delayLockRef.current) return;
const container = containerRef.current;
const text = textRef.current;
if (!container || !text) return;
if (containerRefWidth >= textRefWidth) {
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(${containerRefWidth}px)`;
}
const distance = initial ? textRefWidth : containerRefWidth + textRefWidth;
animatingRef.current = true;
setTimeout(() => {
text.style.transitionDuration = `${Math.round(distance / speed)}s`;
text.style.transform = `translateX(-${textRefWidth}px)`;
}, 500);
}
useEffect(() => {
setTimeout(() => {
Taro.createSelectorQuery().select(`#${containerRefId}`).boundingClientRect(rect => {
setContainerRefWidth(rect.width);
}).exec();
Taro.createSelectorQuery().select(`#${textRefId}`).boundingClientRect(rect => {
setTextRefWidth(rect.width);
}).exec();
}, 0);
}, []);
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(View, {
className: classNames(classPrefix, `${classPrefix}-${props.color}`)
}, props.icon && React.createElement(View, {
className: `${classPrefix}-left`
}, props.icon), React.createElement(View, {
ref: containerRef,
id: containerRefId,
className: `${classPrefix}-content`
}, React.createElement(View, {
onTransitionEnd: () => {
animatingRef.current = false;
start();
},
ref: textRef,
id: textRefId,
className: `${classPrefix}-content-inner`
}, props.content)), (props.closeable || props.extra) && React.createElement(View, {
className: `${classPrefix}-right`
}, props.extra, props.closeable && React.createElement(View, {
className: `${classPrefix}-close`,
onClick: () => {
var _a;
setVisible(false);
(_a = props.onClose) === null || _a === void 0 ? void 0 : _a.call(props);
}
}, React.createElement(CloseIcon, {
className: `${classPrefix}-close-icon`
})))));
});