UNPKG

@nutui/nutui-react

Version:

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

92 lines (91 loc) 3.58 kB
import { _ as __rest } from "./tslib.es6.js"; import React__default, { useRef, useImperativeHandle, useEffect } from "react"; import classNames from "classnames"; import { C as ComponentDefaults } from "./typings.js"; const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { list: [], interval: 500, loop: true, duration: 3e3, rows: 3, gapY: 10 }); const classPrefix = `nut-barrage`; const InternalBarrage = (props, ref) => { const _a = Object.assign(Object.assign({}, defaultProps), props), { className, interval, loop, list, duration, rows, gapY } = _a, restProps = __rest(_a, ["className", "interval", "loop", "list", "duration", "rows", "gapY"]); const barrageBody = useRef(null); const barrageContainer = useRef(null); const barrageCWidth = useRef(0); const timer = useRef(0); const index = useRef(0); const times = useRef([]); const historyIndex = useRef(-1); const classes = classNames(classPrefix, className); useImperativeHandle(ref, () => ({ add: (word) => { const _index = index.current % list.length; if (!loop && index.current === list.length) { list.splice(list.length, 0, word); } else { list.splice(_index, 0, word); } } })); useEffect(() => { if (barrageBody.current) { barrageCWidth.current = barrageBody.current.offsetWidth; } setTimeout(() => { var _a2; (_a2 = barrageBody.current) === null || _a2 === void 0 ? void 0 : _a2.style.setProperty("--move-distance", `-${barrageCWidth.current}px`); index.current = 0; run(); }, 300); return () => { clearInterval(timer.current); }; }, [list]); const run = () => { clearInterval(timer.current); let intervalCache = interval; const _index = (loop ? index.current % list.length : index.current) % rows; const result = times.current[_index] - rows * interval; if (result > 0) { intervalCache += result; } timer.current = window.setTimeout(() => { play(); }, intervalCache); }; const play = () => { if (!loop && index.current >= list.length) { return; } const _index = loop ? index.current % list.length : index.current; const el = document.createElement(`div`); let currentIndex = _index % rows; if (currentIndex <= historyIndex.current || historyIndex.current === 3 && currentIndex !== 0 || Math.abs(currentIndex - historyIndex.current) !== 1) { currentIndex = historyIndex.current + 1 >= rows ? 0 : historyIndex.current + 1; } historyIndex.current = currentIndex; el.innerHTML = list[_index]; el.classList.add("barrage-item"); barrageContainer.current.appendChild(el); const width = el.offsetWidth; const height = el.offsetHeight; el.classList.add("move"); const elScrollDuration = Math.ceil(width / barrageCWidth.current * duration); times.current[currentIndex] = elScrollDuration; el.style.animationDuration = `${duration + elScrollDuration}ms`; el.style.top = `${currentIndex * (height + gapY) + 20}px`; el.style.width = `${width}px`; el.addEventListener("animationend", () => { barrageContainer.current.removeChild(el); }); index.current++; run(); }; return React__default.createElement( "div", Object.assign({ className: classes, ref: barrageBody }, restProps), React__default.createElement("div", { ref: barrageContainer, className: "bContainer" }) ); }; const Barrage = React__default.forwardRef(InternalBarrage); Barrage.displayName = "NutBarrage"; export { Barrage as default };