UNPKG

@nutui/nutui-react-taro

Version:

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

198 lines (197 loc) 8.02 kB
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 };