gpt4 book ai didi

javascript - 在读取模式下显示平均评分,在写入模式下仅显示总值或一半值

转载 作者:行者123 更新时间:2023-11-30 19:59:29 25 4
gpt4 key购买 nike

我正在尝试在功能必须遵循的地方创建星级:

In read mode, the stars are shown as per average (should support 100% i.e 5 or 96% i.e 4.6) in write mode, the user can only rate 1, 1.5, 2, 2.5 etc not 2.6

读取模式按预期工作,但写入模式有问题。写入模式的问题是我无法使用从 1 到 5 的非十进制值以及 1.5、2.5、3.5 等半值更新评级。悬停时如何确定我的鼠标指针是在全星还是半星星星?有人可以看看这个吗?

我已经创建了一个用于演示的沙箱

在这里

https://codesandbox.io/s/9l6kmnw7vw

代码如下

更新代码

// @flow

import React from "react";
import styled, { css } from "styled-components";

const StyledIcon = styled.i`
display: inline-block;
width: 12px;
overflow: hidden;
direction: ${props => props.direction && props.direction};
${props => props.css && css(...props.css)};
`;

const StyledRating = styled.div`
unicode-bidi: bidi-override;
font-size: 25px;
height: 25px;
width: 125px;
margin: 0 auto;
position: relative;
padding: 0;
text-shadow: 0px 1px 0 #a2a2a2;
color: grey;
`;

const TopStyledRating = styled.div`
padding: 0;
position: absolute;
z-index: 1;
display: block;
top: 0;
left: 0;
overflow: hidden;
${props => props.css && css(...props.css)};
width: ${props => props.width && props.width};
`;

const BottomStyledRating = styled.div`
padding: 0;
display: block;
z-index: 0;
`;

class Rating extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
rating: this.props.rating || null,
// eslint-disable-next-line
temp_rating: null
};
}

handleMouseover(rating) {
console.log("rating", rating);
this.setState(prev => ({
rating,
// eslint-disable-next-line
temp_rating: prev.rating
}));
}

handleMouseout() {
this.setState(prev => ({
rating: prev.temp_rating
}));
}

rate(rating) {
this.setState({
rating,
// eslint-disable-next-line
temp_rating: rating
});
}

calculateWidth = value => {
const { total } = this.props;
const { rating } = this.state;
return Math.floor((rating / total) * 100).toFixed(2) + "%";
};

render() {
const { disabled, isReadonly } = this.props;
const { rating } = this.state;
const topStars = [];
const bottomStars = [];
const writableStars = [];
console.log("rating", rating);
// eslint-disable-next-line
if (isReadonly) {
for (let i = 0; i < 5; i++) {
topStars.push(<span>★</span>);
}
for (let i = 0; i < 5; i++) {
bottomStars.push(<span>★</span>);
}
} else {
// eslint-disable-next-line
for (let i = 0; i < 10; i++) {
let klass = "star_border";
if (rating >= i && rating !== null) {
klass = "star";
}
writableStars.push(
<StyledIcon
direction={i % 2 === 0 ? "ltr" : "rtl"}
className="material-icons"
css={this.props.css}
onMouseOver={() => !disabled && this.handleMouseover(i)}
onFocus={() => !disabled && this.handleMouseover(i)}
onClick={() => !disabled && this.rate(i)}
onMouseOut={() => !disabled && this.handleMouseout()}
onBlur={() => !disabled && this.handleMouseout()}
>
{klass}
</StyledIcon>
);
}
}
return (
<React.Fragment>
{isReadonly ? (
<StyledRating>
<TopStyledRating
css={this.props.css}
width={this.calculateWidth(this.props.rating)}
>
{topStars}
</TopStyledRating>
<BottomStyledRating>{bottomStars}</BottomStyledRating>
</StyledRating>
) : (
<React.Fragment>
{rating}
{writableStars}
</React.Fragment>
)}
</React.Fragment>
);
}
}

Rating.defaultProps = {
css: "",
disabled: false
};

export default Rating;

现在,当悬停和单击时,可写的星星是单独完成的,以显示星星的状态,但是当我提供 5 级评级时,它填充的是第三颗星而不是第五颗星。

最佳答案

我认为您当前的问题似乎与鼠标事件的设置位置有关,因为您在单个星星上处理它,它们消失并触发 mouseout 事件,导致这种不断的切换可见性。

我宁愿在外面的div上设置评级检测,然后跟踪鼠标相对于div的位置,并据此设置可写星星的宽度。

我试着从头开始制作一个示例,它展示了如何处理来自外部 div 的更改。我确信我使用的公式仍然可以简化,但是没关系,这只是为了演示它是如何工作的。

const { Component } = React;

const getRating = x => (parseInt(x / 20) * 20 + (x % 20 >= 13 ? 20 : x % 20 >= 7 ? 10 : 0));

class Rating extends Component {
constructor() {
super();
this.state = {
appliedRating: '86%'
};
this.setParentElement = this.setParentElement.bind( this );
this.handleMouseOver = this.handleMouseOver.bind( this );
this.applyRating = this.applyRating.bind( this );
this.reset = this.reset.bind( this );
this.stopReset = this.stopReset.bind( this );
}
stopReset() {
clearTimeout( this.resetTimeout );
}
setParentElement(e) {
this.parentElement = e;
}
handleMouseOver(e) {
this.stopReset();
if (e.currentTarget !== this.parentElement) {
return;
}
const targetRating = getRating(e.clientX - this.parentElement.offsetLeft);
if (this.state.setRating !== targetRating) {
this.setState({
setRating: targetRating
});
}
}
applyRating(e) {
this.setState({
currentRating: this.state.setRating
});
}
reset(e) {
this.resetTimeout = setTimeout(() => this.setState( { setRating: null } ), 50 );
}
renderStars( width, ...classes ) {
return (
<div
onMouseEnter={this.stopReset}
className={ ['flex-rating', ...classes].join(' ')}
style={{width}}>
<span onMouseEnter={this.stopReset} className="star">★</span>
<span onMouseEnter={this.stopReset} className="star">★</span>
<span onMouseEnter={this.stopReset} className="star">★</span>
<span onMouseEnter={this.stopReset} className="star">★</span>
<span onMouseEnter={this.stopReset} className="star">★</span>
</div>
);
}
renderFixed() {
return this.renderStars('100%', 'fixed');
}
renderReadOnlyRating() {
const { appliedRating } = this.state;
return this.renderStars( appliedRating, 'readonly' );
}
renderWriteRating() {
let { setRating, currentRating } = this.state;
if (setRating === 0) {
setRating = '0%';
}
if (currentRating === undefined) {
currentRating = '100%';
}
return this.renderStars( setRating || currentRating, 'writable' );
}
render() {
return (
<div>
<div
ref={ this.setParentElement }
className="rating"
onMouseMove={ this.handleMouseOver }
onMouseOut={ this.reset }
onClick={ this.applyRating }>
{ this.renderFixed() }
{ this.renderReadOnlyRating() }
{ this.renderWriteRating() }
</div>
<div>Current rating: { ( ( this.state.currentRating || 0 ) / 20) }</div>
</div>
);
}
}

ReactDOM.render( <Rating />, document.getElementById('container') );
body { margin: 50px; }
.rating {
font-family: 'Courier new';
font-size: 16px;
position: relative;
display: inline-block;
width: 100px;
height: 25px;
align-items: flex-start;
justify-content: center;
align-content: center;
background-color: white;
}
.flex-rating {
position: absolute;
top: 0;
left: 0;
display: flex;
height: 100%;
overflow: hidden;
cursor: pointer;
}
.fixed {
color: black;
font-size: 1.1em;
font-weight: bold;
}
.readonly {
color: silver;
font-weight: bold;
}
.writable {
color: blue;
background-color: rgba(100, 100, 100, .5);
}
.star {
text-align: center;
width: 20px;
max-width: 20px;
min-width: 20px;
}
<script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
<script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
<div id="container"></div>

关于javascript - 在读取模式下显示平均评分,在写入模式下仅显示总值或一半值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53553263/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com