Настройка полу-иконок с рейтинговой системой - PullRequest
11 голосов
/ 30 мая 2020

Я создал компонент, который по сути представляет собой рейтинговую систему, которая позволяет добавлять дополнительные значки в зависимости от раскрывающегося списка.

Мне было интересно, есть ли способ сделать половину звезд, я просмотрел старый код на inte rnet, но ничего не было обновлено. Любая помощь будет оценена

import React, { useState } from 'react'
import {FaStar} from "react-icons/all";
import './Rater.css'


const Rater = () => {
    const [rating, setRating] = useState(null)
    const [hover, setHover] = useState(null)
    const [value] = useState(100)
    const [iconValue, setIconValue] = useState(5)


    return (
        <div>
            <select onChange={(e) =>
            {setIconValue(Number(e.target.value))}}>
                { Array.from(new Array(value),(value, index) =>
                    index + 1).map(value => <option
                    key={value} value={value}>{value}</option>) }
            </select>
            <h1> Select Amount of Icons </h1>


            {[... Array(iconValue)].map((icon, i) => {
                const value = i + 1

                return (
                    <label>
                        <input type='radio'
                               name='rating'
                               value={value}
                               onClick={() => setRating(value)}
                        />
                        <FaStar classname='star'
                                color={value <= (hover || rating) ? '#ffc107' : '#e4e5e9'}
                                size={100}
                                onMouseEnter={() => setHover(value)}
                                onMouseLeave={() => setHover(null)}
                        />
                    </label>
                )
            })}
        </div>
    )
}

export default Rater

Ответы [ 2 ]

6 голосов
/ 01 июня 2020

Я посмотрел ваш код, ваша звездочка находится в SVG. Вы можете написать шаблон градиента и добавить fill: url(#id) к звезде, которую хотите изменить

.linear-gradient-template {
  width: 0;
  height: 0;
}
<svg class="linear-gradient-template">
    <linearGradient id="orange_grey" x1="0%" y1="0%" x2="100%" y2="0%">
        <stop offset="50%" style="stop-color: rgb(255, 193, 7)"></stop>
        <stop offset="50%" style="stop-color: rgb(228, 229, 233)"></stop>
    </linearGradient>
</svg>

<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 576 512" class="one,star" color="#ffc107" size="100" height="100" width="100" xmlns="http://www.w3.org/2000/svg" style="color: rgb(255, 193, 7);">
  <path style="fill: url(#orange_grey)" d="M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z"></path>
 </svg>

<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 576 512" class="one,star" color="#ffc107" size="100" height="100" width="100" xmlns="http://www.w3.org/2000/svg" style="color: rgb(255, 193, 7);">
  <path style="fill: url(#orange_grey)" d="M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z"></path>
 </svg>

<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 576 512" class="one,star" color="#ffc107" size="100" height="100" width="100" xmlns="http://www.w3.org/2000/svg" style="color: rgb(255, 193, 7);">
  <path style="fill: url(#orange_grey)" d="M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z"></path>
 </svg>
    import React, { useState } from 'react'
import {FaStar} from "react-icons/all";
import './Rater.css'


const Rater = () => {
    const [rating, setRating] = useState(null)
    const [hover, setHover] = useState(null)
    const [value] = useState(100)
    const [iconValue, setIconValue] = useState(5)
    const size = 100

    return (
        <div id="start-wrap">
            <svg className="linear-gradient-template">
                <linearGradient id="orange_red" x1="0%" y1="0%" x2="100%" y2="0%">
                    <stop offset="50%" style={{stopColor: 'rgb(255, 193, 7)'}}></stop>
                    <stop offset="50%" style={{stopColor: 'rgb(228, 229, 233)'}}></stop>
                </linearGradient>
            </svg>
            <select onChange={(e) =>
            {setIconValue(Number(e.target.value))}}>
                { Array.from(new Array(value),(value, index) =>
                    index + 1).map(value => <option
                    key={value} value={value}>{value}</option>) }
            </select>
            <h1> Select Amount of Icons </h1>
            {[... Array(iconValue)].map((icon, i) => {
                const value = i + 1
                return (
                    <label>
                        <input type='radio'
                            name='rating'
                            value={value}
                            onClick={() => setRating(value)}
                        />
                        <FaStar
                            className='star'
                            color={value <= (hover || rating) ? '#ffc107' : '#e4e5e9'}
                            size={size}
                            onMouseEnter={(e) => setHover(value)}
                            onMouseLeave={() => {
                                let svgDom = document.getElementsByClassName('star')[i]
                                let pathDom = svgDom.children[0]
                                pathDom.style.fill = ''
                                setHover(null)
                            }}
                            onMouseMove={e => {
                                let svgDom = document.getElementsByClassName('star')[i]
                                let pathDom = svgDom.children[0]
                                if(e.pageX - svgDom.getBoundingClientRect().left <= size / 2){
                                    pathDom.style.fill = 'url(#orange_red)'
                                } else {
                                    pathDom.style.fill = ''
                                }
                            }}
                        />
                    </label>
                )
            })}
        </div>
    )
}

export default Rater

Выше я изменяю ваш код, он не идеален, вы можете изменить его в соответствии со своими потребностями.

enter image description here

0 голосов
/ 30 мая 2020

Существует несколько способов достижения sh, простой из которых (я не знаю, лучше ли это для вашего приложения) может использовать слои дерева: фон, прозрачный значок и еще один, который будет быть «заливкой» звезды.

Затем вы можете расположить звезду внутри фона и поместить слой «заливки» за звездой. Затем вы устанавливаете ширину слоя заливки в соответствии с рейтингом.

Другой вариант может использовать два значка: один для закрашенной звезды, а другой для половинной звезды. Вы также можете использовать многоугольники для представления звезд и манипулировать точками с помощью CSS. Я думаю, что многоуровневое решение лучше, потому что вам не нужно будет экспортировать новый актив значка или напрямую манипулировать полигонами, все, что вам нужно, - это расположить некоторые блоки div один над другим и управлять их шириной в зависимости от величины скорости

...