@nutui/nutui-react
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
92 lines (91 loc) • 3.58 kB
JavaScript
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
};