各種偏門捷徑實現如圖所示的評分組件
一、低配版
const rate = (num) =>"★★★★★☆☆☆☆☆".substring(5 - num, 10 - num);
沒錯,只需一行代碼就能實現評分(狗頭)
雖然星星的樣式一言難盡,也沒有星星的交互,但這種實現方式你想到過嗎?
二、標準版
rc-rate 的實現思路,ant-design 就是用的這個 rate 組件
首先實現單個星星 Star 組件
import React from 'react';
export default class Star extends React.Component {
onHover = e => {
const { onHover, index } = this.props;
onHover(e, index);
};
onClick = e => {
const { onClick, index } = this.props;
onClick(e, index);
};
getClassName() {
// 根據當前評分修改 star 的 class
const { index, value } = this.props;
const starValue = index + 1;
let className = starValue <= value ? 'full' : 'zero';
return className;
}
render() {
const { onHover, onClick } = this;
const { index, count, value, character } = this.props;
// character 用於自定義星星圖標
const characterNode = typeof character === 'function' ? character(this.props) : character;
const start = (
<li className={this.getClassName()}>
<div
onClick={onClick}
onMouseMove={onHover}
role="radio"
aria-checked={value > index ? 'true' : 'false'}
aria-posinset={index + 1}
aria-setsize={count}
>
{/* 如果要做半星,就把 characterNode 拆成兩個 div */}
{characterNode}
</div>
</li>
);
return start;
}
}
在 Star 組件中,暴露出 onClick 和 onHover 事件
然後基於當前評分 value 和當前位置 index 來切換自身的 class,以實現普通狀態和高亮狀態
然後是 Rate 組件:
import React from 'react';
import Star from './star';
export default class Rate extends React.Component {
constructor(props) {
super(props);
this.state = {
value: undefined,
hoverValue: undefined,
};
}
// 鼠標移出組件時,清空 hoverValue
onMouseLeave = () => {
this.setState({
hoverValue: undefined,
});
};
onClick = (event, index) => {
this.onMouseLeave();
this.setState({
value: index + 1,
});
};
onHover = (event, index) => {
this.setState({
hoverValue: index + 1,
});
};
render() {
const {
count,
className,
character,
} = this.props;
const { value, hoverValue } = this.state;
const stars = [];
// 根據當前 value 生成所有星星
for (let index = 0; index < count; index += 1) {
stars.push(
<Star
key={index}
index={index}
count={count}
value={hoverValue || value}
onClick={this.onClick}
onHover={this.onHover}
character={character}
/>,
);
}
return (
<ul
className={className}
onMouseLeave={this.onMouseLeave}
role="radiogroup"
>
{stars}
</ul>
);
}
}
在 Rate 組件中主要記錄了實際評分 value 和 hover 狀態下的臨時評分 hoverValue
當鼠標移動的時候,以 hoverValue 渲染組件
當鼠標移出 Rate 組件時清空 hoverValue,以 value 渲染組件
三、青春版
這種方案以 CSS 爲主,HTML 部分相當簡單:
攤平了也就是一個簡單的 div 包裹了幾個 input-radio 元素,這些 radio 都添加了同一個 name
接下來就用神奇的 CSS 一步一步實現評分組件的交互
首先實現選中元素時的效果
/* less */
@color-full: coral;
@color-zero: #eee;
.rate {
margin: 0;
padding: 0;
// 重置原本的 input-radio 樣式
input[name="rate"] {
-webkit-appearance: none;
border: none;
outline: none;
cursor: pointer;
background: @color-zero;
// 點擊評分後的效果
&:checked,
// 鼠標移入的效果
&:hover {
background: @color-full;
}
}
}
通過 radio 選中時的 :checked 狀態,可以修改其點擊後的樣式
然後再通過相鄰元素選擇器 ~ ,修改兄弟元素的樣式
input[name="rate"] {
// 點擊評分後的效果
&:checked,
&:hover,
// 兄弟元素的樣式
&:checked ~ input[name="rate"],
&:hover ~ input[name="rate"] {
background: @color-full;
}
}
只是這時候的評分是反向的,沒關係,用 flex-flow: row-reverse; 將元素反向排列即可
.rate {
display: flex;
flex-flow: row-reverse;
}
最後通過 data-set 給 radio 綁定值即可實現取值,不再贅述
參考資料: