UNPKG

@nutui/nutui-react

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

426 lines (425 loc) 17.1 kB
import { _ as _define_property } from "@swc/helpers/_/_define_property"; import { _ as _object_spread } from "@swc/helpers/_/_object_spread"; import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props"; import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { Close, Notice } from "@nutui/icons-react"; import classNames from "classnames"; import { getRect } from "../../hooks/use-client-rect"; import { ComponentDefaults } from "../../utils/typings"; import { useRtl } from "../configprovider"; var defaultProps = _object_spread_props(_object_spread({}, ComponentDefaults), { align: 'left', direction: 'horizontal', list: [], duration: 1000, height: 40, content: '', closeable: false, wrap: false, leftIcon: /*#__PURE__*/ React.createElement(Notice, { width: 16, height: 16 }), rightIcon: null, right: null, delay: 1, scrollable: null, speed: 50 }); export var NoticeBar = function(props) { var rtl = useRtl(); var _$_object_spread = _object_spread({}, defaultProps, props), children = _$_object_spread.children, className = _$_object_spread.className, style = _$_object_spread.style, align = _$_object_spread.align, direction = _$_object_spread.direction, list = _$_object_spread.list, duration = _$_object_spread.duration, height = _$_object_spread.height, content = _$_object_spread.content, closeable = _$_object_spread.closeable, wrap = _$_object_spread.wrap, leftIcon = _$_object_spread.leftIcon, rightIcon = _$_object_spread.rightIcon, right = _$_object_spread.right, delay = _$_object_spread.delay, scrollable = _$_object_spread.scrollable, speed = _$_object_spread.speed, close = _$_object_spread.close, click = _$_object_spread.click, onClose = _$_object_spread.onClose, onClick = _$_object_spread.onClick, onItemClick = _$_object_spread.onItemClick; var classPrefix = 'nut-noticebar'; var wrapRef = useRef(null); var contentRef = useRef(null); var _useState = _sliced_to_array(useState(true), 2), showNoticeBar = _useState[0], SetShowNoticeBar = _useState[1]; var scrollList = useRef([]); var _useState1 = _sliced_to_array(useState(0), 2), wrapWidth = _useState1[0], SetWrapWidth = _useState1[1]; var _useState2 = _sliced_to_array(useState(true), 2), firstRound = _useState2[0], SetFirstRound = _useState2[1]; var _useState3 = _sliced_to_array(useState(0), 2), animationDuration = _useState3[0], SetAnimationDuration = _useState3[1]; var _useState4 = _sliced_to_array(useState(0), 2), offsetWidth = _useState4[0], SetOffsetW = _useState4[1]; var _useState5 = _sliced_to_array(useState(''), 2), animationClass = _useState5[0], SetAnimationClass = _useState5[1]; var _useState6 = _sliced_to_array(useState(false), 2), animate = _useState6[0], SetAnimate = _useState6[1]; var _useState7 = _sliced_to_array(useState(0), 2), timer = _useState7[0], SetTimer = _useState7[1]; var _useState8 = _sliced_to_array(useState(null), 2), isCanScroll = _useState8[0], SetIsCanScroll = _useState8[1]; var isVertical = direction === 'vertical'; var _useState9 = _sliced_to_array(useState(null), 2), rect = _useState9[0], setRect = _useState9[1]; var active = 0; var _useState10 = _sliced_to_array(useState(false), 2), ready = _useState10[0], setReady = _useState10[1]; var container = useRef(null); var innerRef = useRef(null); var swiperRef = useRef({ moving: false, autoplayTimer: null, width: 0, height: 0, offset: 0, size: 0 }); var _useState11 = _sliced_to_array(useState([]), 2), childOffset = _useState11[0], setChildOffset = _useState11[1]; var _useState12 = _sliced_to_array(useState(0), 2), offset = _useState12[0], setOffset = _useState12[1]; var _useMemo = useMemo(function() { var childCount = 0; var childs = React.Children.map(children, function(child) { if (!/*#__PURE__*/ React.isValidElement(child)) return null; childCount++; return child; }); return { childs: childs, childCount: childCount }; }, [ children ]), childs = _useMemo.childs, childCount = _useMemo.childCount; // 滚动消息的总高度 var trackSize = childCount * Number(height); // 设置最小偏移量(最后一条的偏移位置) var minOffset = function() { if (rect) { var base = isVertical ? rect.height : rect.width; return base - Number(height) * childCount; } return 0; }(); useEffect(function() { if (isVertical) { if (children) { scrollList.current = [].concat(childs); } else { scrollList.current = [].concat(list); startRollEasy(); } } else { initScrollWrap(content); } return function() { // 销毁事件 clearInterval(timer); }; }, []); useEffect(function() { initScrollWrap(content); }, [ content ]); useEffect(function() { if (list && list.length) { scrollList.current = [].concat(list); } }, [ list ]); var initScrollWrap = function(value) { if (showNoticeBar === false) { return; } setTimeout(function() { if (!wrapRef.current || !contentRef.current) { return; } var wrapW = getRect(wrapRef.current).width; var offsetW = getRect(contentRef.current).width; var canScroll = align === 'left' && scrollable == null ? offsetW > wrapW : scrollable; SetIsCanScroll(canScroll); if (canScroll) { SetWrapWidth(wrapW); SetOffsetW(offsetW); SetAnimationDuration(offsetW / speed); SetAnimationClass('play'); } else { SetAnimationClass(''); } }, 0); }; var handleClick = function(event) { click && click(event); onClick && onClick(event); }; var onClickIcon = function(event) { event.stopPropagation(); SetShowNoticeBar(!closeable); close && close(event); onClose && onClose(event); }; var onAnimationEnd = function() { SetFirstRound(false); setTimeout(function() { SetAnimationDuration((offsetWidth + wrapWidth) / speed); SetAnimationClass('play-infinite'); }, 0); }; // 滚动时间间隔 var time = height / speed / 4 < 1 ? Number((height / speed / 4).toFixed(1)) * 1000 : ~~(height / speed / 4) * 1000; /** * 滚动方式一,普通垂直滚动 */ var startRollEasy = function() { showhorseLamp(); var timerCurr = window.setInterval(showhorseLamp, time + Number(duration)); SetTimer(timerCurr); }; var showhorseLamp = function() { SetAnimate(true); setTimeout(function() { scrollList.current.push(scrollList.current[0]); scrollList.current.shift(); SetAnimate(false); }, time); }; // 点击滚动单元 var handleClickIcon = function(event) { event.stopPropagation(); SetShowNoticeBar(!closeable); close && close(event); onClose && onClose(event); }; var isEllipsis = function() { if (isCanScroll == null && align === 'left') { return wrap; } return !isCanScroll && !wrap; }; var contentStyle = { animationDelay: "".concat(firstRound ? delay : 0, "s"), animationDuration: "".concat(animationDuration, "s"), transform: "translateX(".concat(firstRound ? 0 : "".concat(rtl ? -wrapWidth : wrapWidth, "px"), ")") }; var barStyle = { height: isVertical ? "".concat(height, "px") : '' }; var duringTime = height / speed / 4 < 1 ? Number((height / speed / 4).toFixed(1)) : ~~(height / speed / 4); var noDuring = height / speed < 1 ? (height / speed).toFixed(1) : ~~(height / speed); var horseLampStyle = { transition: animate ? "all ".concat(duringTime === 0 ? noDuring : duringTime, "s") : '', marginTop: animate ? "-".concat(height, "px") : '' }; // 垂直自定义滚动方式 var init = function() { var active = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : +0; var rects = getRect(container === null || container === void 0 ? void 0 : container.current); var _active = Math.max(Math.min(childCount - 1, active), 0); var _height = rects.height; trackSize = childCount * Number(_height); var targetOffset = getOffset(_active); swiperRef.current.moving = true; if (ready) { swiperRef.current.moving = false; } active = _active; setRect(rects); setOffset(targetOffset); setReady(true); }; useEffect(function() { if (ready) { stopAutoPlay(); autoplay(); } return function() { setReady(false); }; }, [ ready ]); useEffect(function() { if (isVertical && children) { init(); stopAutoPlay(); autoplay(); } }, [ children, container === null || container === void 0 ? void 0 : container.current ]); // 清除定时器 var stopAutoPlay = function() { clearTimeout(swiperRef.current.autoplayTimer); swiperRef.current.autoplayTimer = null; }; // 定时轮播 var autoplay = function() { if (childCount <= 1) return; stopAutoPlay(); swiperRef.current.autoplayTimer = setTimeout(function() { next(); autoplay(); }, Number(duration) + 100 * speed); }; // 切换方法 var move = function(param) { var _param_pace = param.pace, pace = _param_pace === void 0 ? 0 : _param_pace, _param_offset = param.offset, offset = _param_offset === void 0 ? 0 : _param_offset; if (childCount <= 1) return; var targetActive = getActive(pace); // 父级容器偏移量 var targetOffset = getOffset(targetActive, offset); // 循环滚动,调整开头结尾图片位置 if (Array.isArray(children) && children[0] && targetOffset !== minOffset) { var rightBound = targetOffset < minOffset; childOffset[0] = rightBound ? trackSize : 0; } if (Array.isArray(children) && children[childCount - 1] && targetOffset !== 0) { var leftBound = targetOffset > 0; childOffset[childCount - 1] = leftBound ? -trackSize : 0; } setChildOffset(childOffset); active = targetActive; setOffset(targetOffset); getStyle(targetOffset); }; // 下一页 var next = function() { resettPosition(); requestFrame(function() { requestFrame(function() { swiperRef.current.moving = false; move({ pace: 1 }); }); }); }; var handleItemClick = function(event, value) { onItemClick && onItemClick(event, value); }; var getStyle = function() { var moveOffset = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : offset; var target = innerRef.current; if (!target) { return; } var _offset = 0; // 容器高度-元素高度 var val = rect.height - height; _offset = moveOffset + Number(active === childCount - 1 && val / 2); target.style.transitionDuration = "".concat(swiperRef.current.moving ? 0 : duration, "ms"); target.style.height = "".concat(Number(height) * childCount, "px"); target.style.transform = "translate3D(0,".concat(_offset, "px,0)"); }; // 无缝滚动第一个元素位移控制 var itemStyle = function(index) { var style = {}; if (height) { style.height = "".concat(height, "px"); style.lineHeight = "".concat(height, "px"); } var offset = childOffset[index]; if (offset) { style.transform = "translate3D(0,".concat(offset, "px,0)"); } return style; }; // 确定当前active 元素 var getActive = function(pace) { if (pace) { var _active = active + pace; return range(_active, -1, childCount); } return active; }; // 计算位移 var getOffset = function(active) { var offset = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0; var currentPosition = active * Number(height); var targetOffset = offset - currentPosition; return targetOffset; }; // 浏览器 帧 事件 var requestFrame = function(fn) { window.requestAnimationFrame.call(window, fn); }; // 取值 方法 var range = function(num, min, max) { return Math.min(Math.max(num, min), max); }; // 重置首尾位置信息 var resettPosition = function() { swiperRef.current.moving = true; if (active <= -1) { move({ pace: childCount }); } if (active >= childCount) { move({ pace: -childCount }); } }; var _obj; var noticebarClass = classNames((_obj = {}, _define_property(_obj, "".concat(classPrefix, "-box"), true), _define_property(_obj, "".concat(classPrefix, "-box-wrapable"), wrap), _define_property(_obj, "".concat(classPrefix, "-box-").concat(align), true), _obj)); var cls = classNames(classPrefix, className); useEffect(function() { return function() { stopAutoPlay(); }; }, []); return /*#__PURE__*/ React.createElement("div", { className: cls, style: style }, showNoticeBar && direction === 'horizontal' ? /*#__PURE__*/ React.createElement("div", { className: noticebarClass, style: barStyle, onClick: handleClick }, leftIcon ? /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-box-left-icon" }, leftIcon) : null, /*#__PURE__*/ React.createElement("div", { ref: wrapRef, className: "nut-noticebar-box-wrap" }, /*#__PURE__*/ React.createElement("div", { ref: contentRef, className: "nut-noticebar-box-wrap-content ".concat(animationClass, " ").concat(isEllipsis() ? 'nut-ellipsis' : ''), style: contentStyle, onAnimationEnd: onAnimationEnd }, children, content)), right ? /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-box-right" }, right) : null, closeable || rightIcon ? /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-box-right-icon", onClick: onClickIcon }, rightIcon || /*#__PURE__*/ React.createElement(Close, { width: 12, height: 12 })) : null) : null, showNoticeBar && scrollList.current.length > 0 && isVertical ? /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-vertical", style: barStyle, ref: container, onClick: handleClick }, leftIcon ? /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-box-left-icon" }, leftIcon) : null, children ? /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-box-wrap", ref: innerRef }, scrollList.current.map(function(item, index) { return /*#__PURE__*/ React.createElement("div", { style: itemStyle(index), key: index, onClick: function(e) { handleItemClick(e, item); } }, item); })) : /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-box-horseLamp-list", style: horseLampStyle }, scrollList.current.map(function(item, index) { return(// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-box-horseLamp-list-item", style: { height: height }, key: index, onClick: function(e) { handleItemClick(e, item); } }, item)); })), /*#__PURE__*/ React.createElement("div", { className: "nut-noticebar-box-right-icon", onClick: function(e) { handleClickIcon(e); } }, rightIcon || (closeable ? /*#__PURE__*/ React.createElement(Close, { width: 12, height: 12 }) : null))) : null); }; NoticeBar.displayName = 'NutNoticeBar';