@nutui/nutui-react
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
94 lines (93 loc) • 3.43 kB
JavaScript
import React__default, { useState, useRef, useEffect } from "react";
import { Top } from "@nutui/icons-react";
import classNames from "classnames";
import { C as ComponentDefaults } from "./typings.js";
import { r as requestAniFrame } from "./raf.js";
import { useRtl } from "./ConfigProvider.js";
const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { target: "", threshold: 200, zIndex: 900, duration: 1e3 });
const BackTop = (props) => {
const rtl = useRtl();
const { children, target, threshold, zIndex, className, duration, style, onClick } = Object.assign(Object.assign({}, defaultProps), props);
const classPrefix = "nut-backtop";
const [backTop, SetBackTop] = useState(false);
const [scrollTop, SetScrollTop] = useState(0);
let startTime = 0;
const scrollEl = useRef(null);
useEffect(() => {
init();
return () => removeEventListener();
}, []);
const init = () => {
if (target && document.getElementById(target)) {
scrollEl.current = document.getElementById(target);
} else {
scrollEl.current = window;
}
addEventListener();
initCancelAniFrame();
};
const scrollListener = () => {
let top = null;
if (scrollEl.current instanceof Window) {
top = scrollEl.current.pageYOffset;
SetScrollTop(top);
} else {
top = scrollEl.current.scrollTop;
SetScrollTop(top);
}
const showBtn = top >= threshold;
SetBackTop(showBtn);
};
const scroll = (y = 0) => {
if (scrollEl.current instanceof Window) {
window.scrollTo(0, y);
} else {
scrollEl.current.scrollTop = y;
window.scrollTo(0, y);
}
};
const scrollAnimation = () => {
let cid = requestAniFrame(function fn() {
const t = duration - Math.max(0, startTime - +/* @__PURE__ */ new Date() + duration / 2);
const y = t * -scrollTop / duration + scrollTop;
scroll(y);
cid = requestAniFrame(fn);
if (t === duration || y === 0) {
window.cancelAnimationFrame(cid);
}
});
};
const initCancelAniFrame = () => {
window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
};
function addEventListener() {
var _a, _b;
(_a = scrollEl.current) === null || _a === void 0 ? void 0 : _a.addEventListener("scroll", scrollListener, false);
(_b = scrollEl.current) === null || _b === void 0 ? void 0 : _b.addEventListener("resize", scrollListener, false);
}
function removeEventListener() {
var _a, _b;
(_a = scrollEl.current) === null || _a === void 0 ? void 0 : _a.removeEventListener("scroll", scrollListener, false);
(_b = scrollEl.current) === null || _b === void 0 ? void 0 : _b.removeEventListener("resize", scrollListener, false);
}
const goTop = (e) => {
onClick && onClick(e);
const otime = +/* @__PURE__ */ new Date();
startTime = otime;
duration > 0 ? scrollAnimation() : scroll();
};
const styles = Object.keys(style || {}).length !== 0 ? Object.assign({ zIndex }, style) : {
[rtl ? "left" : "right"]: "10px",
bottom: "20px",
zIndex
};
return React__default.createElement("div", { className: classNames(classPrefix, {
show: backTop
}, className), style: styles, onClick: (e) => {
goTop(e);
} }, children || React__default.createElement(Top, { width: 19, height: 19, className: "nut-backtop-main" }));
};
BackTop.displayName = "NutBackTop";
export {
BackTop as default
};