@nutui/nutui-react-taro
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
133 lines (132 loc) • 4.74 kB
JavaScript
import React__default, { useState, useRef, useEffect } from "react";
import classNames from "classnames";
import { StarFill } from "@nutui/icons-react-taro";
import { useReady } from "@tarojs/taro";
import { View } from "@tarojs/components";
import { C as ComponentDefaults } from "./typings-DV9RBfhj.js";
import { u as usePropsValue } from "./use-props-value-SH9krhkx.js";
import { g as getRectByTaro } from "./get-rect-by-taro-D0h6aiDr.js";
import { u as useRefs } from "./use-refs-BeEmziIR.js";
const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { count: 5, min: 0, checkedIcon: null, uncheckedIcon: null, disabled: false, readOnly: false, allowHalf: false, touchable: false });
const Rate = (props) => {
const { className, style, count, value, defaultValue, min, checkedIcon, uncheckedIcon, disabled, readOnly, allowHalf, touchable, onChange, onTouchEnd } = Object.assign(Object.assign({}, defaultProps), props);
const classPrefix = "nut-rate";
const [countArray, setCountArray] = useState([1, 2, 3, 4, 5]);
const [refs, setRefs] = useRefs();
const rateRects = useRef([]);
const [score, setScore] = usePropsValue({
value,
defaultValue: Math.max(defaultValue || 0, min),
finalValue: 0,
onChange
});
useEffect(() => {
const tmp = [];
for (let i = 1; i <= Number(count); i++) {
tmp.push(i);
}
setCountArray(tmp);
}, [count]);
const renderIcon = (n) => {
return n <= score ? checkedIcon || React__default.createElement(StarFill, null) : uncheckedIcon || (checkedIcon ? React__default.cloneElement(checkedIcon, {
color: void 0
}) : React__default.createElement(StarFill, null));
};
const onClick = (e, index) => {
e.preventDefault();
e.stopPropagation();
if (disabled || readOnly)
return;
let value2 = 0;
if (!(index === 1 && score === index)) {
value2 = index;
}
value2 = Math.max(value2, min);
setScore(value2);
};
const onHalfClick = (event, n) => {
event.preventDefault();
event.stopPropagation();
const value2 = Math.max(min, n - 0.5);
setScore(value2);
};
const getScoreByPosition = (x) => {
var _a;
if ((_a = rateRects.current) === null || _a === void 0 ? void 0 : _a.length) {
for (let index = rateRects.current.length - 1; index >= 0; index--) {
const item = rateRects.current[index];
if (item && x > item.left) {
return allowHalf ? index + (x > item.left + item.width / 2 ? 1 : 0.5) : index + 1;
}
}
return 0;
}
};
const updateRects = () => {
for (let index = 0; index < refs.length; index++) {
const item = refs[index];
if (item) {
getRectByTaro(item).then((res) => {
rateRects.current[index] = res;
});
}
}
};
useReady(() => {
updateRects();
});
const handleTouchStart = (e) => {
if (!touchable || readOnly || disabled) {
return;
}
if (e.cancelable) {
e.preventDefault();
}
e.stopPropagation();
updateRects();
};
const handleTouchMove = (e) => {
if (!touchable || readOnly || disabled) {
return;
}
if (e.cancelable) {
e.preventDefault();
}
e.stopPropagation();
const val = getScoreByPosition(e.touches[0].clientX);
if (val !== void 0) {
setScore(Math.max(min, val));
}
};
const handleTouchEnd = (e) => {
if (!touchable || readOnly || disabled) {
return;
}
if (e.cancelable) {
e.preventDefault();
}
e.stopPropagation();
const val = getScoreByPosition(e.changedTouches[0].clientX);
if (val !== void 0) {
setScore(Math.max(min, val));
onTouchEnd && onTouchEnd(e, Math.max(min, val));
}
};
return React__default.createElement(View, { className: classNames(classPrefix, {
disabled,
readonly: readOnly
}, className), catchMove: true, style, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, onTouchCancel: handleTouchEnd }, countArray.map((n, index) => {
return React__default.createElement(
"div",
{ className: `${classPrefix}-item`, key: n, ref: setRefs(index), onClick: (event) => onClick(event, n) },
React__default.createElement("div", { className: classNames(`${classPrefix}-item-icon`, {
[`${classPrefix}-item-icon-disabled`]: disabled || n > score
}) }, renderIcon(n)),
allowHalf && score > n - 1 && React__default.createElement("div", { className: classNames(`${classPrefix}-item-half`, `${classPrefix}-item-icon`, `${classPrefix}-item-icon-half`), onClick: (event) => onHalfClick(event, n) }, renderIcon(n))
);
}));
};
Rate.displayName = "NutRate";
export {
Rate as R
};