各種偏門捷徑實現如圖所示的評分組件

一、低配版
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 綁定值即可實現取值,不再贅述
參考資料:
