68 lines
2.0 KiB
React
68 lines
2.0 KiB
React
import React, { useState } from 'react';
|
||
import './Rate.css';
|
||
|
||
/**
|
||
* Aurora Admin Rate(React)
|
||
* 对齐 组件7.txt RateInput 规范:星级、半星、只读、尺寸、文字
|
||
*
|
||
* props:
|
||
* - value / defaultValue : 评分数值
|
||
* - count : 星数(默认 5)
|
||
* - allowHalf: 允许半星
|
||
* - readonly / disabled
|
||
* - size : 'default' | 'sm' | 'lg'
|
||
* - showText : 是否显示评分文字
|
||
* - texts : 文字数组
|
||
* - onChange(value)
|
||
*/
|
||
const DEFAULT_TEXTS = ['极差', '失望', '一般', '满意', '惊喜'];
|
||
|
||
export default function Rate({
|
||
value,
|
||
defaultValue = 0,
|
||
count = 5,
|
||
allowHalf = false,
|
||
readonly = false,
|
||
disabled = false,
|
||
size = 'default',
|
||
showText = false,
|
||
texts = DEFAULT_TEXTS,
|
||
onChange
|
||
}) {
|
||
const [inner, setInner] = useState(defaultValue);
|
||
const current = value !== undefined ? value : inner;
|
||
|
||
const stars = Array.from({ length: count }, (_, i) => Math.max(0, Math.min(1, current - i)));
|
||
const textLabel = current ? texts[Math.ceil(current) - 1] : '未评分';
|
||
|
||
const choose = (evt, i) => {
|
||
if (readonly || disabled) return;
|
||
let next = i + 1;
|
||
if (allowHalf) {
|
||
const rect = evt.currentTarget.getBoundingClientRect();
|
||
const half = (evt.clientX - rect.left) < rect.width / 2;
|
||
next = half ? i + 0.5 : i + 1;
|
||
}
|
||
if (next === current) next = 0;
|
||
if (value === undefined) setInner(next);
|
||
onChange && onChange(next);
|
||
};
|
||
|
||
return (
|
||
<div className={`aa-rate${size !== 'default' ? ' ' + size : ''}${readonly ? ' is-readonly' : ''}${disabled ? ' is-disabled' : ''}`}>
|
||
{stars.map((s, i) => (
|
||
<span key={i} className="aa-rate-star" onClick={(e) => choose(e, i)}>
|
||
★<span className="aa-rate-fill" style={{ width: (s * 100) + '%' }}>★</span>
|
||
</span>
|
||
))}
|
||
{showText && <span className="aa-rate-text">{textLabel}</span>}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
/*
|
||
用法示例:
|
||
import Rate from './Rate';
|
||
<Rate count={5} allowHalf defaultValue={2.5} showText onChange={setScore} />
|
||
*/
|