我正在努力使定制评分组件。我知道还有其他的库,但我想自己来做,这样我就可以理解底层的过程了。然而,我在自定义组件部分上苦苦挣扎。对于默认情况,它工作得很好。对于自定义组件,我尝试的是允许开发人员传递他们所需图标的svg组件,然后将该图标显示为评级组件。到目前为止,它是工作的,但我不知道如何处理鼠标移出功能。
以下是我尝试过的方法
import React from "react";
const DefaultComponent = ({
ratingRef,
currentRating,
handleMouseOut,
handleMouseOver,
handleStarClick,
totalRating
}) => {
return (
<div
className="rating"
ref={ratingRef}
data-rating={currentRating}
onMouseOut={handleMouseOut}
>
{[...Array(+totalRating).keys()].map(n => {
return (
<span
className="star"
key={n + 1}
data-value={n + 1}
onMouseOver={handleMouseOver}
onClick={handleStarClick}
>
★
</span>
);
})}
</div>
);
};
const CustomComponent = ({
ratingRef,
currentRating,
handleMouseOut,
handleMouseOver,
handleStarClick,
totalRating,
ratingComponent
}) => {
return (
<>
{[...Array(+totalRating).keys()].map(n => {
return ratingComponent({ key: n });
})}
</>
);
};
const Rating = props => {
const { totalRating = 5, onClick, ratingComponent } = props;
const [currentRating, setCurrentRating] = React.useState(0);
React.useEffect(() => {
handleMouseOut();
}, []);
const handleMouseOver = ev => {
const stars = ev.target.parentElement.getElementsByClassName("star");
const hoverValue = ev.target.dataset.value;
Array.from(stars).forEach(star => {
star.style.color = hoverValue >= star.dataset.value ? "#FDC60A" : "#444";
});
};
const handleMouseOut = ev => {
const stars = ratingRef?.current?.getElementsByClassName("star");
stars &&
Array.from(stars).forEach(star => {
star.style.color =
currentRating >= star.dataset.value ? "#FDC60A" : "#444";
});
};
const handleStarClick = ev => {
let rating = ev.target.dataset.value;
setCurrentRating(rating); // set state so the rating stays highlighted
if (onClick) {
onClick(rating); // emit the event up to the parent
}
};
const ratingRef = React.useRef();
console.log("ratingComponent", ratingComponent);
return (
<>
{ratingComponent ? (
<CustomComponent
ratingRef={ratingRef}
currentRating={currentRating}
handleMouseOut={handleMouseOut}
handleMouseOver={handleMouseOver}
handleStarClick={handleStarClick}
totalRating={totalRating}
ratingComponent={ratingComponent}
/>
) : (
<DefaultComponent
ratingRef={ratingRef}
currentRating={currentRating}
handleMouseOut={handleMouseOut}
handleMouseOver={handleMouseOver}
handleStarClick={handleStarClick}
totalRating={totalRating}
/>
)}
</>
);
};
export default Rating;我还创建了一个沙箱。
https://codesandbox.io/s/stoic-almeida-yz7ju?file=/src/components/Rating/Rating.js:0-2731
谁能告诉我如何制作可重用的评级组件,它可以支持自定义图标进行评级,就像我需要的那样,我需要的正是宝石和星形图标?
发布于 2020-06-09 22:20:37
我会这样做:
DefaultComponent以接收图标fill或color属性hoverIndex状态来跟踪我正在悬停的元素并将悬停事件放在DefaultComponent内,因为它们只与图标相关,在父容器中不需要
我在设计star svg时遇到了问题。从本质上讲,您需要覆盖它的fill颜色-但这似乎是一个复杂的颜色。如果您可以简化它,或者将填充作为prop传递到svg中并在内部使用它-这两种方法都可以!
沙盒:https://codesandbox.io/s/epic-pascal-j1d0c
希望这能有所帮助!
const DefaultIcon = _ => "a"; // = '★'
const DefaultComponent = ({
ratingComponent = DefaultIcon,
ratingRef,
currentRating,
handleStarClick,
totalRating
}) => {
const RatingIconComponent = ratingComponent;
const [hoverIndex, setHoverIndex] = React.useState(-Infinity);
const handleMouseOver = index => {
setHoverIndex(index);
};
const handleMouseOut = ev => {
setHoverIndex(-Infinity);
};
return (
<div
className="rating"
ref={ratingRef}
data-rating={currentRating}
onMouseOut={handleMouseOut}
>
{[...Array(+totalRating).keys()].map(n => {
const isFilled = n < currentRating || n <= hoverIndex;
return (
<span
className={`ratingIcon ${isFilled && "fill"}`}
key={n + 1}
data-value={n + 1}
onMouseOver={_ => handleMouseOver(n)}
onClick={_ => handleStarClick(n + 1)}
>
<RatingIconComponent />
</span>
);
})}
</div>
);
};const Rating = props => {
const { totalRating = 5, onClick, ratingComponent } = props;
const [currentRating, setCurrentRating] = React.useState(0);
const handleStarClick = rating => {
setCurrentRating(rating); // set state so the rating stays highlighted
if (onClick) {
onClick(rating); // emit the event up to the parent
}
};
const ratingRef = React.useRef();
return (
<DefaultComponent
ratingComponent={ratingComponent}
ratingRef={ratingRef}
currentRating={currentRating}
handleStarClick={handleStarClick}
totalRating={totalRating}
/>
);
};<Rating ratingComponent={Gem} />/* for normal text */
.ratingIcon {
color: "gray";
}
.ratingIcon.fill {
color: yellow;
}
/* for svg */
.ratingIcon svg path {
fill: gray !important;
}
.ratingIcon.fill svg path {
fill: yellow !important;
}https://stackoverflow.com/questions/62283605
复制相似问题