評分組件 Rate 的別樣解法

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

 

一、低配版

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 綁定值即可實現取值,不再贅述

 

 

參考資料:

《tiny-rate》

《react-component/rate》

《講道理,僅3行核心css代碼的rate評分組件,我被自己秀到頭皮發麻》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章