尝试使用React,顺风CSS和Headless UI做出5星评级



尝试构建一个5星评级组件,就像示例链接。

peer-hover似乎起作用,但peer-checked不像peer-hover那样起作用。

(items包含一个数组[1,2,3,4,5])

你能指出发生这个问题的原因吗?

import { RadioGroup } from '@headlessui/react'
import { useController } from "react-hook-form";
import { classNames } from '../libs/frontend/utils'
import { StarIcon } from '@heroicons/react/24/outline';
import { StarIcon as StarIconSolid } from '@heroicons/react/20/solid';
export const RadioGroupStars = (props) => {
const {
field: { value, onChange }
} = useController(props);
const { items } = props;
return (
<>
<RadioGroup
value={value}
onChange={onChange}
className="w-full my-1">
<RadioGroup.Label className="sr-only"> Choose a option </RadioGroup.Label>
<div className="flex flex-row-reverse justify-center gap-1">
{items.map((item) => (
<RadioGroup.Option
key={item}
value={item}
className={({ active, checked }) =>
classNames(
'cursor-pointer text-gray-200',
'flex-1 hover:text-yellow-600',
'peer',
'peer-hover:text-yellow-600 peer-checked:text-yellow-500',
active ? 'text-yellow-500' : '',
checked ? 'text-yellow-500' : '',
)
}
>
<RadioGroup.Label as={StarIconSolid} className='' />
</RadioGroup.Option>
))}
</div>
</RadioGroup>
</>
);
}

我认为peer-checked不工作的原因可能是因为RadioGroup.Option输出div包装图标为Label(而不是input),因此伪类:checked不应用,而peer-hover确实工作。

因为组件可以访问选定的value并且额定值是可比较的:

项包含数组[1,2,3,4,5]

RadioGroup.Option可以将自己的值与选择的值进行比较,作为不同类渲染的条件(或者等价地比较index)。

由于此列表还使用flex-row-reverse来实现兄弟悬停,因此考虑将reverse()放在map()之前的items,以保持迭代项的正确顺序。

在live on: stackblitz中测试了这个例子(为了简单起见省略了react-hook-form的逻辑):

<div className="flex flex-row-reverse justify-center gap-1">
{[...items].reverse().map((item) => (
<RadioGroup.Option
key={item}
value={item}
className={({ active, checked }) =>
classNames(
"cursor-pointer text-gray-200",
"flex-1 hover:text-yellow-400",
"peer",
"peer-hover:text-yellow-400",
active ? "text-yellow-500" : "",
checked ? "text-yellow-500" : "",
// 👇 Add a compare with selected value here
value >= item ? "text-yellow-500" : ""
)
}
>
<RadioGroup.Label as={BsStarFill} className="w-6 h-6" />
</RadioGroup.Option>
))}
</div>

另一方面,因为RadioGroup需要setValue(一个状态set函数)来处理它的onChangeprop,所以不太确定useController()返回的field.onChange是否可以与它一起工作。

如果没有,也许可以考虑在组件中托管一个状态,并与useController同步,这样它的函数仍然可以被使用。

我在下面的代码中使用了react和tailwing,尽可能使用简单的控件

export default function RatingControl() {
const [rating, setRating] = useState(0);
return (
<div className="grid w-full sm:col-span-3 sm:grid-cols-10">
<dt className="pb-2 font-bold text-gray-500 sm:col-span-10 ">
Rate Survey
</dt>
{Array.from({ length: 5 }, (_, k) => k + 1).map((item) => (
<button
key={`buttonItem${item}`}
type="button"
onClick={() => {
setRating(item);
}}
className={classNames(
rating !== item ? 'bg-black' : 'bg-gray-800',
' mr-4 mt-2 lg:mt-0 rounded-md text-lg font-semibold text-gray-500 shadow-sm hover:text-white hover:bg-gray-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white'
)}
>
{item}
</button>
))}
</div>
);
}

相关内容

  • 没有找到相关文章

最新更新