@nutui/nutui-react-taro
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
198 lines (197 loc) • 8.02 kB
JavaScript
import { _ as __rest } from "./tslib.es6-iWu3F_1J.js";
import React__default, { createContext, useRef, useState, useEffect } from "react";
import Taro, { nextTick, createSelectorQuery } from "@tarojs/taro";
import { ScrollView } from "@tarojs/components";
import classNames from "classnames";
import { C as ComponentDefaults } from "./typings-DV9RBfhj.js";
import { u as useUuid } from "./use-uuid-BvqmbYZ7.js";
const elevatorContext = createContext({});
const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { height: "200px", floorKey: "title", list: [], sticky: false, spaceHeight: 23, titleHeight: 35, showKeys: true, className: "weapp-elevator" });
const Elevator = (props) => {
const _a = Object.assign(Object.assign({}, defaultProps), props), { height, floorKey, list, sticky, spaceHeight, titleHeight, showKeys, className, style, onItemClick, onIndexClick, children } = _a, rest = __rest(_a, ["height", "floorKey", "list", "sticky", "spaceHeight", "titleHeight", "showKeys", "className", "style", "onItemClick", "onIndexClick", "children"]);
const uuid = useUuid();
const classPrefix = "nut-elevator";
const listview = useRef(null);
const initData = {
anchorIndex: 0,
listHeight: [],
listGroup: [],
scrollY: 0
};
const touchState = useRef({
y1: 0,
y2: 0
});
const [currentData, setCurrentData] = useState({});
const [currentKey, setCurrentKey] = useState("");
const [codeIndex, setCodeIndex] = useState(0);
const [scrollStart, setScrollStart] = useState(false);
const state = useRef(initData);
const scrolling = useRef(false);
const [scrollTop, setScrollTop] = useState(0);
const [scrollY, setScrollY] = useState(0);
const resetScrollState = () => {
setScrollStart(false);
};
const getData = (el) => {
if (!el.dataset.index) {
return "0";
}
return el.dataset.index;
};
const calculateHeight = () => {
let height2 = 0;
state.current.listHeight.push(height2);
for (let i = 0; i < state.current.listGroup.length; i++) {
const query = createSelectorQuery();
query.selectAll(`.${classPrefix}-${uuid} .nut-elevator-item-${i}`).boundingClientRect();
query.exec((res) => {
if (res[0][0])
height2 += res[0][0].height;
state.current.listHeight.push(height2);
});
}
};
const scrollTo = (index) => {
if (!index && index !== 0) {
return;
}
if (!state.current.listHeight.length) {
calculateHeight();
}
let cacheIndex = index;
if (index < 0) {
cacheIndex = 0;
}
if (index > state.current.listHeight.length - 2) {
cacheIndex = Math.max(0, state.current.listHeight.length - 2);
}
setCodeIndex(cacheIndex);
const scrollTop2 = state.current.listHeight[cacheIndex];
setScrollTop(scrollTop2);
if (sticky && scrollY !== scrollTop2) {
setScrollY(Math.floor(scrollTop2) > 0 ? 1 : 0);
}
};
const touchMove = (e) => {
const firstTouch = e.touches[0];
touchState.current.y2 = firstTouch.pageY;
const delta = (touchState.current.y2 - touchState.current.y1) / spaceHeight || 0;
const cacheIndex = state.current.anchorIndex + Math.floor(delta);
setCodeIndex(cacheIndex);
scrollTo(cacheIndex);
};
const touchEnd = () => {
resetScrollState();
};
const touchStart = (e) => {
const index = Number(getData(e.target));
const firstTouch = e.touches[0];
scrolling.current = true;
touchState.current.y1 = firstTouch.pageY;
state.current.anchorIndex = +index;
setScrollStart(true);
setCodeIndex(index);
scrollTo(index);
};
const handleClickItem = (key, item) => {
onItemClick && onItemClick(key, item);
setCurrentData(item);
setCurrentKey(key);
};
const handleClickIndex = (key) => {
onIndexClick && onIndexClick(key);
};
const setListGroup = () => {
if (listview.current) {
createSelectorQuery().selectAll(`.${classPrefix}-${uuid} .nut-elevator-list-item`).node((el) => {
state.current.listGroup = [...Object.keys(el)];
calculateHeight();
}).exec();
}
};
const listViewScroll = (e) => {
const { listHeight } = state.current;
if (!listHeight.length) {
calculateHeight();
}
const target = e.target;
const { scrollTop: scrollTop2 } = target;
state.current.scrollY = Math.floor(scrollTop2);
Taro.getEnv() === "WEB" && setScrollTop(scrollTop2);
if (sticky && scrollTop2 !== scrollY) {
setScrollY(Math.floor(scrollTop2) > 0 ? 1 : 0);
}
if (scrolling.current)
return;
for (let i = 0; i < listHeight.length - 1; i++) {
const height1 = listHeight[i];
const height2 = listHeight[i + 1];
if (state.current.scrollY >= height1 && state.current.scrollY < height2) {
return setCodeIndex(i);
}
}
};
useEffect(() => {
if (listview.current) {
nextTick(() => {
setListGroup();
});
}
}, [listview]);
return React__default.createElement(
"div",
Object.assign({ className: `${classPrefix} ${className} ${classPrefix}-${uuid}`, style }, rest),
React__default.createElement(
"div",
{ className: `${classPrefix}-list`, style: { height: Number.isNaN(+height) ? height : `${height}px` } },
React__default.createElement(ScrollView, { scrollTop, scrollY: true, scrollWithAnimation: true, scrollAnchoring: true, className: `${classPrefix}-list-inner`, type: "list", ref: listview, onScroll: listViewScroll, onTouchStart: (e) => {
scrolling.current = false;
} }, list.map((item, idx) => {
return React__default.createElement(
"div",
{ className: `${classPrefix}-list-item nut-elevator-item-${idx}`, key: idx },
React__default.createElement("div", { className: `${classPrefix}-list-item-code` }, item[floorKey]),
React__default.createElement(React__default.Fragment, null, item.list.map((subitem) => {
return React__default.createElement("div", { className: classNames({
[`${classPrefix}-list-item-name`]: true,
[`${classPrefix}-list-item-name-highcolor`]: currentData.id === subitem.id && currentKey === item[floorKey]
}), key: subitem.id, onClick: () => handleClickItem(item[floorKey], subitem) }, children ? React__default.createElement(
React__default.Fragment,
null,
React__default.createElement(elevatorContext.Provider, { value: subitem }, children)
) : subitem.name);
}))
);
}))
),
showKeys ? React__default.createElement(
React__default.Fragment,
null,
list.length && scrollStart ? React__default.createElement("div", { className: classNames({
[`${classPrefix}-code-current`]: true,
[`${classPrefix}-code-current-current`]: true
}) }, list[codeIndex][floorKey]) : null,
React__default.createElement(
"div",
{ className: `${classPrefix}-bars` },
React__default.createElement("div", { className: `${classPrefix}-bars-inner`, onTouchStart: (event) => touchStart(event), onTouchMove: (event) => touchMove(event), onTouchEnd: touchEnd, style: { touchAction: "pan-y" } }, list.map((item, index) => {
return React__default.createElement("div", { className: classNames({
[`${classPrefix}-bars-inner-item`]: true,
[`${classPrefix}-bars-inner-item-active`]: item[floorKey] === list[codeIndex][floorKey]
}), "data-index": index, key: index, onClick: () => handleClickIndex(item[floorKey]) }, item[floorKey]);
}))
)
) : null,
sticky && scrollY > 0 ? React__default.createElement(
"div",
{ className: `${classPrefix}-list-fixed` },
React__default.createElement("span", { className: `${classPrefix}-list-fixed-title` }, list[codeIndex][floorKey])
) : null
);
};
Elevator.displayName = "NutElevator";
Elevator.Context = elevatorContext;
export {
Elevator as E
};