UNPKG

antd-mobile-taro-ui

Version:

以antd-mobile为设计标准,基于taro框架的微信小程序组件库

119 lines (112 loc) 4 kB
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` }))))); });