• 评分组件 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评分组件,我被自己秀到头皮发麻》

  • 相关阅读:
    UVa-133-救济金发放
    UVa-340-猜数字
    UVa-1584-环状序列
    UVa-1585-得分
    UVa-1586-分子量
    BZOJ-3289: Mato的文件管理(莫队算法+树状数组)
    HDU-2824 The Euler function(欧拉函数)
    2017年10月12日22:27:20
    HDU-4715 Difference Between Primes(线性筛法)
    POJ-1185 炮兵阵地(状态压缩DP)
  • 原文地址:https://www.cnblogs.com/wisewrong/p/13614756.html
Copyright © 2020-2023  润新知