PK 组件用于可视化展示两种或多种数据的对比结果,特别适用于需要直观展示竞争或对比分析的场景。
效果展示
小红书 PK 组件
我们将实现一个类似的 PK 组件
2. 组件设计
2.1 设计理念
PK 组件的设计遵循简洁、直观的原则,旨在通过颜色和比例直观展示数据对比。组件的设计允许用户通过简单的配置即可展示复杂的数据对比结果。
2.2 样式和颜色
组件使用了 Ant Design 的颜色库来定义不同的颜色,便于区分不同的数据项,增强视觉识别度。
import { green, orange, red, yellow } from "@ant-design/colors"
const dataKeyMapToColors: Record<string, string[]> = {
'apple': red,
'orange': orange,
'mango': green
}
2.3 数据结构和计算
组件定义了一个 pkData
对象和一个 getSum
函数,用于存储和计算数据项的总和。这种设计使得组件可以轻松地扩展到更多的数据项。
export const pkData = {
'apple': 5,
'orange': 2
}
const getSum = (data: Record<string, number>) => {
return Object.values(data).reduce((accumulator: number, currentValue: any) => accumulator + Number(currentValue || 0), 0)
}
2.4 结果选项生成
generatePkResultOptions
函数是组件的核心,它根据传入的数据对象生成一个结果数组,每个结果对象包含数据项的键、计数、文本、颜色和比例。
export const generatePkResultOptions = (data: Record<string, number>) => {
const res = []
const sum = getSum(data)
for (const [key, value] of Object.entries(data)) {
res.push({
key,
count: value,
text: key,
colors: dataKeyMapToColors[key],
ratio: (value / sum)
})
}
return res
}
2.5 组件样式
使用 styled-components
库定义了两个样式组件 PkResultCardWrapper
和 CardItem
,这些样式组件提供了灵活的样式定制能力。
import styled from "styled-components"
const PkResultCardWrapper = styled.div<{
len?: number
}>`
width: 800px;
display: flex;
justify-content: space-between;
gap: 8px;
flex-wrap: nowrap;
text-align: center;
font-weight: 500;
${(props) =>
props.len === 1
? `
&>div:first-child{
border-radius: 10px 20px !important;
}
`
: `
&>div:first-child{
border-radius: 10px 4px 8px 20px !important;
}
&>div:last-child{
border-radius: 6px 20px 10px 6px !important;
}
`}
`
const CardItem = styled.div<{
colors?: string[]
$width?: string
}>`
height: 32px;
line-height: 30px;
flex-basis: ${props => props.$width};
border-radius: 6px !important;
transform: skewX(-15deg);
span {
display: inline-block;
transform: skewX(15deg);
}
${(props) =>
props.colors
? `
color: ${props.colors?.[5]} !important;
border: 1px solid ${props.colors?.[2]} !important;
background: ${props.colors?.[0]} !important;
`
: ''}
`
2.6 PK 结果卡片组件
PkResultCard
是一个函数组件,它接收一个 options
数组作为参数,并渲染每个结果卡片。这个组件的设计允许它在不同的上下文中重用。
type PkResultCardProps = {
options: PkResultCardOptions[]
}
export function PkResultCard({ options }: PkResultCardProps) {
return (
<PkResultCardWrapper len={options.length} >
{options?.map(option => {
const ratio = (Number(option.ratio) * 100).toFixed(2) + '%'
return (
<CardItem key={option.key} colors={option.colors} $width={ratio}>
{<span>{`${option.text}: ${option.count} - ${ratio}`}</span>}
</CardItem>
)
})}
</PkResultCardWrapper>
)
}
2.7 PK 卡片演示组件
PkCardDemo
是一个演示组件,它使用 React 的 useState
钩子来管理不同数据项的计数,并使用 useMemo
钩子来生成结果选项。这个组件提供了一个交互式的界面,允许用户动态地增加数据项的计数。
import React, { useMemo } from 'react'
import { generatePkResultOptions } from './data'
import { PkResultCard } from './PkResultCard'
import { Button, Space } from 'antd'
export function PkCardDemo() {
const [apple, setApple] = React.useState(1)
const [orange, setOrange] = React.useState(1)
const [mango, setMango] = React.useState(1)
const options = useMemo(() => generatePkResultOptions({ apple, orange, mango }), [apple, orange, mango])
return (
<Space direction='vertical'>
<Space size={8}>
<Button onClick={() => setApple(apple + 1)}>Apple + 1</Button>
<Button onClick={() => setOrange(orange + 1)}>Orange + 1</Button>
<Button onClick={() => setMango(mango + 1)}>Mango + 1</Button>
</Space>
<PkResultCard options={options} />
</Space>
)
}
3. 使用方法
3.1 引入组件
在需要使用 PK 组件的地方,引入 PkCardDemo
。
import { PkCardDemo } from './PkResultCard'
3.2 渲染组件
在 React 应用中渲染 PkCardDemo
组件。
<PkCardDemo />
3.3 定制和扩展
组件的设计允许用户根据需要定制颜色和样式。用户可以通过修改 dataKeyMapToColors
对象来改变不同数据项的颜色。此外,用户可以通过添加更多的数据项到 pkData
对象中来扩展组件。
4. 总结
PK 组件提供了一个直观的方式来展示不同数据项的对比结果。通过颜色编码和比例显示,用户可以快速理解不同数据项的相对大小。组件的设计允许灵活地添加或修改数据项,使其适用于多种场景。通过简单的配置和扩展,PK 组件可以轻松集成到任何需要数据对比展示的 React 应用中。