# Ant Design Component Documentation
This file contains usage examples and parameters for all components.
# Icons 图标集
语义化的矢量图标集合。需要安装 `@hi-ui/icons` 图标组件包,然后从中引入。
## 使用示例
### 通用
```tsx
import React from 'react'
import * as Icons from '@hi-ui/icons'
import message from '@hi-ui/message'
export const Basic = () => {
const icons = React.useMemo(() => {
return [
{
id: 'filled',
title: '面型',
children: [
{ component: Icons.AcceptanceFilled, tagName: 'AcceptanceFilled' },
{ component: Icons.AiFilled, tagName: 'AiFilled' },
{ component: Icons.AlarmClockFilled, tagName: 'AlarmClockFilled' },
{ component: Icons.AlarmFilled, tagName: 'AlarmFilled' },
{ component: Icons.AppStoreFilled, tagName: 'AppStoreFilled' },
{ component: Icons.ApproveFilled, tagName: 'ApproveFilled' },
{ component: Icons.ArchiveFilled, tagName: 'ArchiveFilled' },
{ component: Icons.AssetMonitorFilled, tagName: 'AssetMonitorFilled' },
{ component: Icons.AudioFilled, tagName: 'AudioFilled' },
{ component: Icons.BankCardFilled, tagName: 'BankCardFilled' },
{ component: Icons.BellFilled, tagName: 'BellFilled' },
{ component: Icons.BlockFilled, tagName: 'BlockFilled' },
{ component: Icons.BookmarkFilled, tagName: 'BookmarkFilled' },
{ component: Icons.BoxFilled, tagName: 'BoxFilled' },
{ component: Icons.BuildingFilled, tagName: 'BuildingFilled' },
{ component: Icons.BulbFilled, tagName: 'BulbFilled' },
{ component: Icons.BusinessCardFilled, tagName: 'BusinessCardFilled' },
{
component: Icons.BusinessCardTransverseFilled,
tagName: 'BusinessCardTransverseFilled',
},
{ component: Icons.CalculatorFilled, tagName: 'CalculatorFilled' },
{ component: Icons.CalendarFilled, tagName: 'CalendarFilled' },
{ component: Icons.CallFilled, tagName: 'CallFilled' },
{ component: Icons.CameraFilled, tagName: 'CameraFilled' },
{ component: Icons.Car2Filled, tagName: 'Car2Filled' },
{ component: Icons.CarFilled, tagName: 'CarFilled' },
{ component: Icons.CertificateFilled, tagName: 'CertificateFilled' },
{ component: Icons.Chat2Filled, tagName: 'Chat2Filled' },
{ component: Icons.ChatFilled, tagName: 'ChatFilled' },
{ component: Icons.CloudDownloadFilled, tagName: 'CloudDownloadFilled' },
{ component: Icons.CloudFilled, tagName: 'CloudFilled' },
{ component: Icons.CloudUploadFilled, tagName: 'CloudUploadFilled' },
{ component: Icons.CollectionFilled, tagName: 'CollectionFilled' },
{ component: Icons.CompassFilled, tagName: 'CompassFilled' },
{ component: Icons.CustomerServiceFilled, tagName: 'FrameFilled' },
{ component: Icons.DataMonitorFilled, tagName: 'DataMonitorFilled' },
{ component: Icons.DislikeFilled, tagName: 'DislikeFilled' },
{ component: Icons.DocumentExclamationFilled, tagName: 'DocumentExclamationFilled' },
{ component: Icons.DocumentFilled, tagName: 'DocumentFilled' },
{ component: Icons.DocumentVideoFilled, tagName: 'DocumentVideoFilled' },
{ component: Icons.DocumentZipFilled, tagName: 'DocumentZipFilled' },
{ component: Icons.EndDateFilled, tagName: 'EndDateFilled' },
{ component: Icons.ExpressionFilled, tagName: 'ExpressionFilled' },
{ component: Icons.FireFilled, tagName: 'FireFilled' },
{ component: Icons.FlagFilled, tagName: 'FlagFilled' },
{ component: Icons.FolderFilled, tagName: 'FolderFilled' },
{ component: Icons.FolderOpenFilled, tagName: 'FolderOpenFilled' },
{ component: Icons.GlassesFilled, tagName: 'GlassesFilled' },
{ component: Icons.GlobalFilled, tagName: 'GlobalFilled' },
{ component: Icons.HeadphonesFilled, tagName: 'HeadphonesFilled' },
{ component: Icons.HeartFilled, tagName: 'HeartFilled' },
{ component: Icons.HomeFilled, tagName: 'HomeFilled' },
{ component: Icons.InStockFilled, tagName: 'InStockFilled' },
{ component: Icons.KeyFilled, tagName: 'KeyFilled' },
{ component: Icons.LeaseFilled, tagName: 'LeaseFilled' },
{ component: Icons.LightningFilled, tagName: 'LightningFilled' },
{ component: Icons.LikeFilled, tagName: 'LikeFilled' },
{ component: Icons.LocationFilled, tagName: 'LocationFilled' },
{ component: Icons.LockFilled, tagName: 'LockFilled' },
{ component: Icons.LoudspeakerFilled, tagName: 'LoudspeakerFilled' },
{ component: Icons.MailFilled, tagName: 'MailFilled' },
{ component: Icons.MailOpenFilled, tagName: 'MailOpenFilled' },
{ component: Icons.MailSendFilled, tagName: 'MailSendFilled' },
{ component: Icons.ManFilled, tagName: 'ManFilled' },
{ component: Icons.MessageFilled, tagName: 'MessageFilled' },
{ component: Icons.MobileFilled, tagName: 'MobileFilled' },
{ component: Icons.MonitorFilled, tagName: 'MonitorFilled' },
{ component: Icons.MoonFilled, tagName: 'MoonFilled' },
{ component: Icons.PadFilled, tagName: 'PadFilled' },
{ component: Icons.PauseFilled, tagName: 'PauseFilled' },
{ component: Icons.Phone2Filled, tagName: 'Phone2Filled' },
{ component: Icons.Phone3Filled, tagName: 'Phone3Filled' },
{ component: Icons.PhoneFilled, tagName: 'PhoneFilled' },
{ component: Icons.PictureFilled, tagName: 'PictureFilled' },
{ component: Icons.PinFilled, tagName: 'PinFilled' },
{ component: Icons.PlayFilled, tagName: 'PlayFilled' },
{ component: Icons.PositionFilled, tagName: 'PositionFilled' },
{ component: Icons.PrinterFilled, tagName: 'PrinterFilled' },
{ component: Icons.QrCodeFilled, tagName: 'QrCodeFilled' },
{ component: Icons.RefrigeratorFilled, tagName: 'RefrigeratorFilled' },
{ component: Icons.RelationFilled, tagName: 'RelationFilled' },
{ component: Icons.RmbFilled, tagName: 'RmbFilled' },
{ component: Icons.RobotFilled, tagName: 'RobotFilled' },
{ component: Icons.RoomFilled, tagName: 'RoomFilled' },
{ component: Icons.SadFilled, tagName: 'SadFilled' },
{ component: Icons.SaveFilled, tagName: 'SaveFilled' },
{ component: Icons.SearchFilled, tagName: 'SearchFilled' },
{ component: Icons.SendOutFilled, tagName: 'SendOutFilled' },
{ component: Icons.SettingFilled, tagName: 'SettingFilled' },
{ component: Icons.ShieldFilled, tagName: 'ShieldFilled' },
{ component: Icons.ShopFilled, tagName: 'ShopFilled' },
{ component: Icons.ShoppingCartFilled, tagName: 'ShoppingCartFilled' },
{ component: Icons.ShoppingFilled, tagName: 'ShoppingFilled' },
{ component: Icons.SkinFilled, tagName: 'SkinFilled' },
{ component: Icons.SmileFilled, tagName: 'SmileFilled' },
{ component: Icons.SoundFilled, tagName: 'SoundFilled' },
{ component: Icons.StarFilled, tagName: 'StarFilled' },
{ component: Icons.StartDateFilled, tagName: 'StartDateFilled' },
{ component: Icons.StockroomFilled, tagName: 'StockroomFilled' },
{ component: Icons.StudentFilled, tagName: 'StudentFilled' },
{ component: Icons.SunFilled, tagName: 'SunFilled' },
{ component: Icons.TagFilled, tagName: 'TagFilled' },
{ component: Icons.TalkFilled, tagName: 'TalkFilled' },
{ component: Icons.TaskFilled, tagName: 'TaskFilled' },
{ component: Icons.TemplateFilled, tagName: 'TemplateFilled' },
{ component: Icons.TimeFilled, tagName: 'TimeFilled' },
{ component: Icons.ToolFilled, tagName: 'ToolFilled' },
{ component: Icons.TranspondFilled, tagName: 'TranspondFilled' },
{ component: Icons.TravelFilled, tagName: 'TravelFilled' },
{ component: Icons.TruckFilled, tagName: 'TruckFilled' },
{ component: Icons.UmberFilled, tagName: 'UmberFilled' },
{ component: Icons.UmbrellaFilled, tagName: 'UmbrellaFilled' },
{ component: Icons.UnlockFilled, tagName: 'UnlockFilled' },
{ component: Icons.UpdateFilled, tagName: 'UpdateFilled' },
{ component: Icons.UserFilled, tagName: 'UserFilled' },
{ component: Icons.VacantFilled, tagName: 'VacantFilled' },
{ component: Icons.VideoCameraFilled, tagName: 'VideoCameraFilled' },
{ component: Icons.VipFilled, tagName: 'VipFilled' },
{ component: Icons.VoiceFilled, tagName: 'VoiceFilled' },
{ component: Icons.WashMachineFilled, tagName: 'WashMachineFilled' },
{ component: Icons.WebpageFilled, tagName: 'WebpageFilled' },
{ component: Icons.WorkOrderFilled, tagName: 'WorkOrderFilled' },
],
},
{
id: 'outlined',
title: '线型',
children: [
{ component: Icons.AcceptanceOutlined, tagName: 'AcceptanceOutlined' },
{ component: Icons.AiOutlined, tagName: 'AiOutlined' },
{ component: Icons.AlarmClockOutlined, tagName: 'AlarmClockOutlined' },
{ component: Icons.AlarmOutlined, tagName: 'AlarmOutlined' },
{ component: Icons.AppStoreOutlined, tagName: 'AppStoreOutlined' },
{ component: Icons.ApproveOutlined, tagName: 'ApproveOutlined' },
{ component: Icons.ArchiveOutlined, tagName: 'ArchiveOutlined' },
{ component: Icons.AreaOutlined, tagName: 'AreaOutlined' },
{ component: Icons.AssetMonitorOutlined, tagName: 'AssetMonitorOutlined' },
{ component: Icons.AssetsOutlined, tagName: 'AssetsOutlined' },
{ component: Icons.AssociateOutlined, tagName: 'AssociateOutlined' },
{ component: Icons.AudioOutlined, tagName: 'AudioOutlined' },
{ component: Icons.BankCardOutlined, tagName: 'BankCardOutlined' },
{ component: Icons.BarcodeOutlined, tagName: 'BarcodeOutlined' },
{ component: Icons.BarsOutlined, tagName: 'BarsOutlined' },
{ component: Icons.BatchUpdateOutlined, tagName: 'BatchUpdateOutlined' },
{ component: Icons.BellOutlined, tagName: 'BellOutlined' },
{ component: Icons.BlockOutlined, tagName: 'BlockOutlined' },
{ component: Icons.BookmarkOutlined, tagName: 'BookmarkOutlined' },
{ component: Icons.BoxOutlined, tagName: 'BoxOutlined' },
{ component: Icons.BuildingOutlined, tagName: 'BuildingOutlined' },
{ component: Icons.BulbOutlined, tagName: 'BulbOutlined' },
{ component: Icons.BusinessCardOutlined, tagName: 'BusinessCardOutlined' },
{
component: Icons.BusinessCardTransverseOutlined,
tagName: 'BusinessCardTransverseOutlined',
},
{ component: Icons.CalculatorOutlined, tagName: 'CalculatorOutlined' },
{ component: Icons.CalendarOutlined, tagName: 'CalendarOutlined' },
{ component: Icons.CallOutlined, tagName: 'CallOutlined' },
{ component: Icons.CameraOutlined, tagName: 'CameraOutlined' },
{ component: Icons.Car2Outlined, tagName: 'Car2Outlined' },
{ component: Icons.CarOutlined, tagName: 'CarOutlined' },
{ component: Icons.CertificateOutlined, tagName: 'CertificateOutlined' },
{ component: Icons.Chat2Outlined, tagName: 'Chat2Outlined' },
{ component: Icons.ChatForwardingOutlined, tagName: 'ChatForwardingOutlined' },
{ component: Icons.ChatOutlined, tagName: 'ChatOutlined' },
{ component: Icons.ClipOutlined, tagName: 'ClipOutlined' },
{ component: Icons.CloseCodeOutlined, tagName: 'CloseCodeOutlined' },
{ component: Icons.ClockOutlined, tagName: 'ClockOutlined' },
{ component: Icons.CloudDownloadOutlined, tagName: 'CloudDownloadOutlined' },
{ component: Icons.CloudOutlined, tagName: 'CloudOutlined' },
{ component: Icons.CloudUploadOutlined, tagName: 'CloudUploadOutlined' },
{ component: Icons.CollectionOutlined, tagName: 'CollectionOutlined' },
{ component: Icons.CommendOutlined, tagName: 'CommendOutlined' },
{ component: Icons.CompassOutlined, tagName: 'CompassOutlined' },
{ component: Icons.ContractOutlined, tagName: 'ContractOutlined' },
{ component: Icons.CustomerServiceOutlined, tagName: 'CustomerServiceOutlined' },
{ component: Icons.DataExportOutlined, tagName: 'DataExportOutlined' },
{ component: Icons.DataMonitorOutlined, tagName: 'DataMonitorOutlined' },
{ component: Icons.DiagramOutlined, tagName: 'DiagramOutlined' },
{ component: Icons.DislikeOutlined, tagName: 'DislikeOutlined' },
{ component: Icons.DocumentExclamationOutlined, tagName: 'DocumentExclamationOutlined' },
{ component: Icons.DocumentOutlined, tagName: 'DocumentOutlined' },
{ component: Icons.DocumentVideoOutlined, tagName: 'DocumentVideoOutlined' },
{ component: Icons.DocumentZipOutlined, tagName: 'DocumentZipOutlined' },
{ component: Icons.DownUpOutlined, tagName: 'DownUpOutlined' },
{ component: Icons.DownloadOutlined, tagName: 'DownloadOutlined' },
{ component: Icons.DragDotOutlined, tagName: 'DragDotOutlined' },
{ component: Icons.EndDateOutlined, tagName: 'EndDateOutlined' },
{ component: Icons.ExportOutlined, tagName: 'ExportOutlined' },
{ component: Icons.ExpressionOutlined, tagName: 'ExpressionOutlined' },
{ component: Icons.EyeInvisibleOutlined, tagName: 'EyeInvisibleOutlined' },
{ component: Icons.EyeOutlined, tagName: 'EyeOutlined' },
{ component: Icons.FireOutlined, tagName: 'FireOutlined' },
{ component: Icons.FlagOutlined, tagName: 'FlagOutlined' },
{ component: Icons.FolderOpenOutlined, tagName: 'FolderOpenOutlined' },
{ component: Icons.FolderOutlined, tagName: 'FolderOutlined' },
{ component: Icons.ForwardOutlined, tagName: 'ForwardOutlined' },
{ component: Icons.FrameOutlined, tagName: 'FrameOutlined' },
{ component: Icons.FreezeOutlined, tagName: 'FreezeOutlined' },
{ component: Icons.GlassesOutlined, tagName: 'GlassesOutlined' },
{ component: Icons.GlobalOutlined, tagName: 'GlobalOutlined' },
{ component: Icons.GuideOutlined, tagName: 'GuideOutlined' },
{ component: Icons.GuidelinesOutlined, tagName: 'GuidelinesOutlined' },
{ component: Icons.HangUpOutlined, tagName: 'HangUpOutlined' },
{ component: Icons.HeadphonesOutlined, tagName: 'HeadphonesOutlined' },
{ component: Icons.HeartOutlined, tagName: 'HeartOutlined' },
{ component: Icons.HeartSimpleOutlined, tagName: 'HeartSimpleOutlined' },
{ component: Icons.HomeOutlined, tagName: 'HomeOutlined' },
{ component: Icons.ImportOutlined, tagName: 'ImportOutlined' },
{ component: Icons.InStockOutlined, tagName: 'InStockOutlined' },
{ component: Icons.KeyOutlined, tagName: 'KeyOutlined' },
{ component: Icons.LeaseOutlined, tagName: 'LeaseOutlined' },
{ component: Icons.LightningOutlined, tagName: 'LightningOutlined' },
{ component: Icons.LikeOutlined, tagName: 'LikeOutlined' },
{ component: Icons.LinkOutlined, tagName: 'LinkOutlined' },
{ component: Icons.LocationOutlined, tagName: 'LocationOutlined' },
{ component: Icons.LockOutlined, tagName: 'LockOutlined' },
{ component: Icons.LoudspeakerOutlined, tagName: 'LoudspeakerOutlined' },
{ component: Icons.MailOpenOutlined, tagName: 'MailOpenOutlined' },
{ component: Icons.MailOutlined, tagName: 'MailOutlined' },
{ component: Icons.MailSendOutlined, tagName: 'MailSendOutlined' },
{ component: Icons.ManOutlined, tagName: 'ManOutlined' },
{ component: Icons.MenuOutlined, tagName: 'MenuOutlined' },
{ component: Icons.MessageOutlined, tagName: 'MessageOutlined' },
{ component: Icons.MobileOutlined, tagName: 'MobileOutlined' },
{ component: Icons.MonitorOutlined, tagName: 'MonitorOutlined' },
{ component: Icons.MoonOutlined, tagName: 'MoonOutlined' },
{ component: Icons.MoveOutlined, tagName: 'MoveOutlined' },
{ component: Icons.OutOfStockOutlined, tagName: 'OutOfStockOutlined' },
{ component: Icons.PadOutlined, tagName: 'PadOutlined' },
{ component: Icons.PauseOutlined, tagName: 'PauseOutlined' },
{ component: Icons.PaymentOutlined, tagName: 'PaymentOutlined' },
{ component: Icons.Phone2Outlined, tagName: 'Phone2Outlined' },
{ component: Icons.Phone3Outlined, tagName: 'Phone3Outlined' },
{ component: Icons.PhoneOutlined, tagName: 'PhoneOutlined' },
{ component: Icons.PictureOutlined, tagName: 'PictureOutlined' },
{ component: Icons.PinOutlined, tagName: 'PinOutlined' },
{ component: Icons.PlayOutlined, tagName: 'PlayOutlined' },
{ component: Icons.PositionOutlined, tagName: 'PositionOutlined' },
{ component: Icons.PowerOffOutlined, tagName: 'PowerOffOutlined' },
{ component: Icons.PrinterOutlined, tagName: 'PrinterOutlined' },
{ component: Icons.QrCodeOutlined, tagName: 'QrCodeOutlined' },
{ component: Icons.QuantityOutlined, tagName: 'QuantityOutlined' },
{ component: Icons.RefrigeratorOutlined, tagName: 'RefrigeratorOutlined' },
{ component: Icons.RelationOutlined, tagName: 'RelationOutlined' },
{ component: Icons.ResetOutlined, tagName: 'ResetOutlined' },
{ component: Icons.RmbOutlined, tagName: 'RmbOutlined' },
{ component: Icons.RobotOutlined, tagName: 'RobotOutlined' },
{ component: Icons.RoomOutlined, tagName: 'RoomOutlined' },
{ component: Icons.SadOutlined, tagName: 'SadOutlined' },
{ component: Icons.ScanOutlined, tagName: 'ScanOutlined' },
{ component: Icons.SearchOutlined, tagName: 'SearchOutlined' },
{ component: Icons.SealOutlined, tagName: 'SealOutlined' },
{ component: Icons.SendOutOutlined, tagName: 'SendOutOutlined' },
{ component: Icons.SettingOutlined, tagName: 'SettingOutlined' },
{ component: Icons.ShareOutlined, tagName: 'ShareOutlined' },
{ component: Icons.ShieldOutlined, tagName: 'ShieldOutlined' },
{ component: Icons.ShopOutlined, tagName: 'ShopOutlined' },
{ component: Icons.ShoppingCartOutlined, tagName: 'ShoppingCartOutlined' },
{ component: Icons.ShoppingOutlined, tagName: 'ShoppingOutlined' },
{ component: Icons.ShowCode2Outlined, tagName: 'ShowCode2Outlined' },
{ component: Icons.ShowCodeOutlined, tagName: 'ShowCodeOutlined' },
{ component: Icons.SkinOutlined, tagName: 'SkinOutlined' },
{ component: Icons.SlashOutlined, tagName: 'SlashOutlined' },
{ component: Icons.SmileOutlined, tagName: 'SmileOutlined' },
{ component: Icons.SoundOutlined, tagName: 'SoundOutlined' },
{ component: Icons.StarOutlined, tagName: 'StarOutlined' },
{ component: Icons.StartDateOutlined, tagName: 'StartDateOutlined' },
{ component: Icons.StockroomOutlined, tagName: 'StockroomOutlined' },
{ component: Icons.StudentOutlined, tagName: 'StudentOutlined' },
{ component: Icons.SunOutlined, tagName: 'SunOutlined' },
{ component: Icons.SwitchOutlined, tagName: 'SwitchOutlined' },
{ component: Icons.SynchronizeOutlined, tagName: 'SynchronizeOutlined' },
{ component: Icons.TagOutlined, tagName: 'TagOutlined' },
{ component: Icons.TalkOutlined, tagName: 'TalkOutlined' },
{ component: Icons.TaskOutlined, tagName: 'TaskOutlined' },
{ component: Icons.TemplateOutlined, tagName: 'TemplateOutlined' },
{ component: Icons.TextExtractionOutlined, tagName: 'TextExtractionOutlined' },
{ component: Icons.TimeOutlined, tagName: 'TimeOutlined' },
{ component: Icons.TimeRewindOutlined, tagName: 'TimeRewindOutlined' },
{ component: Icons.ToolOutlined, tagName: 'ToolOutlined' },
{ component: Icons.TrackingOutlined, tagName: 'TrackingOutlined' },
{ component: Icons.TravelOutlined, tagName: 'TravelOutlined' },
{ component: Icons.TruckOutlined, tagName: 'TruckOutlined' },
{ component: Icons.UmberOutlined, tagName: 'UmberOutlined' },
{ component: Icons.UmbrellaOutlined, tagName: 'UmbrellaOutlined' },
{ component: Icons.UnfreezeOutlined, tagName: 'UnfreezeOutlined' },
{ component: Icons.UnlockOutlined, tagName: 'UnlockOutlined' },
{ component: Icons.UpdateOutlined, tagName: 'UpdateOutlined' },
{ component: Icons.UploadOutlined, tagName: 'UploadOutlined' },
{ component: Icons.UserAddOutlined, tagName: 'UserAddOutlined' },
{ component: Icons.UserOutlined, tagName: 'UserOutlined' },
{ component: Icons.UsersOutlined, tagName: 'UsersOutlined' },
{ component: Icons.VacantOutlined, tagName: 'VacantOutlined' },
{ component: Icons.VideoCameraOutlined, tagName: 'VideoCameraOutlined' },
{ component: Icons.VipOutlined, tagName: 'VipOutlined' },
{ component: Icons.VoiceOutlined, tagName: 'VoiceOutlined' },
{ component: Icons.WarehouseOutlined, tagName: 'WarehouseOutlined' },
{ component: Icons.WashMachineOutlined, tagName: 'WashMachineOutlined' },
{ component: Icons.WebpageOutlined, tagName: 'WebpageOutlined' },
{ component: Icons.WeighingOutlined, tagName: 'WeighingOutlined' },
{ component: Icons.WithdrawOutlined, tagName: 'WithdrawOutlined' },
{ component: Icons.WomanOutlined, tagName: 'WomanOutlined' },
{ component: Icons.WorkOrderOutlined, tagName: 'WorkOrderOutlined' },
],
},
{
id: 'colorful',
title: '多色型',
children: [{ component: Icons.FeedbackColorful, tagName: 'FeedbackColorful' }],
},
]
}, [])
const renderIcon = React.useCallback(({ component: Component, tagName }) => {
return (
{
evt.currentTarget.style.backgroundColor = '#f2f4f7'
evt.currentTarget.style.cursor = 'pointer'
}}
onMouseLeave={(evt) => {
evt.currentTarget.style.backgroundColor = 'transparent'
evt.currentTarget.style.cursor = 'default'
}}
onClick={() => {
try {
const textArea = document.createElement('textarea')
textArea.value = `<${tagName} />`
textArea.style.position = 'fixed'
textArea.style.opacity = '0'
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
message.open({
title: `复制成功:\n<${tagName} />`,
type: 'success',
})
} catch (err) {
console.error('复制失败:', err)
message.open({
title: '复制失败',
type: 'error',
})
}
}}
>
{tagName}
)
}, [])
return (
<>
{icons.map((typeItem) => (
{typeItem.title}
{typeItem.children.map(renderIcon)}
))}
>
)
}
```
### 提示
```tsx
import React from 'react'
import * as Icons from '@hi-ui/icons'
import message from '@hi-ui/message'
export const Alert = () => {
const icons = React.useMemo(() => {
return [
{
id: 'filled',
title: '面型',
children: [
{ component: Icons.AddCircleFilled, tagName: 'AddCircleFilled' },
{ component: Icons.CheckCircleFilled, tagName: 'CheckCircleFilled' },
{ component: Icons.CheckSquareFilled, tagName: 'CheckSquareFilled' },
{ component: Icons.CloseCircleFilled, tagName: 'CloseCircleFilled' },
{ component: Icons.CloseSquareFilled, tagName: 'CloseSquareFilled' },
{ component: Icons.ExclamationCircleFilled, tagName: 'ExclamationCircleFilled' },
{ component: Icons.InfoCircleFilled, tagName: 'InfoCircleFilled' },
{ component: Icons.MinusSquareFilled, tagName: 'MinusSquareFilled' },
{ component: Icons.PlusSquareFilled, tagName: 'PlusSquareFilled' },
{ component: Icons.QuestionCircleFilled, tagName: 'QuestionCircleFilled' },
{ component: Icons.StopFilled, tagName: 'StopFilled' },
{ component: Icons.WarningFilled, tagName: 'WarningFilled' },
],
},
{
id: 'outlined',
title: '线型',
children: [
{ component: Icons.CheckCircleOutlined, tagName: 'CheckCircleOutlined' },
{ component: Icons.CheckOutlined, tagName: 'CheckOutlined' },
{ component: Icons.CheckSquareOutlined, tagName: 'CheckSquareOutlined' },
{ component: Icons.CloseCircleOutlined, tagName: 'CloseCircleOutlined' },
{ component: Icons.CloseOutlined, tagName: 'CloseOutlined' },
{ component: Icons.CloseSquareOutlined, tagName: 'CloseSquareOutlined' },
{ component: Icons.ExclamationCircleOutlined, tagName: 'ExclamationCircleOutlined' },
{ component: Icons.ExclamationOutlined, tagName: 'ExclamationOutlined' },
{ component: Icons.InfoCircleOutlined, tagName: 'InfoCircleOutlined' },
{ component: Icons.InfoOutlined, tagName: 'InfoOutlined' },
{ component: Icons.MinusOutlined, tagName: 'MinusOutlined' },
{ component: Icons.MinusSquareOutlined, tagName: 'MinusSquareOutlined' },
{ component: Icons.PlusOutlined, tagName: 'PlusOutlined' },
{ component: Icons.PlusSquareOutlined, tagName: 'PlusSquareOutlined' },
{ component: Icons.QuestionCircleOutlined, tagName: 'QuestionCircleOutlined' },
{ component: Icons.QuestionOutlined, tagName: 'QuestionOutlined' },
{ component: Icons.StopOutlined, tagName: 'StopOutlined' },
{ component: Icons.WarningOutlined, tagName: 'WarningOutlined' },
],
},
]
}, [])
const renderIcon = React.useCallback(({ component: Component, tagName }) => {
return (
{
evt.currentTarget.style.backgroundColor = '#f2f4f7'
evt.currentTarget.style.cursor = 'pointer'
}}
onMouseLeave={(evt) => {
evt.currentTarget.style.backgroundColor = 'transparent'
evt.currentTarget.style.cursor = 'default'
}}
onClick={() => {
try {
const textArea = document.createElement('textarea')
textArea.value = `<${tagName} />`
textArea.style.position = 'fixed'
textArea.style.opacity = '0'
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
message.open({
title: `复制成功:\n<${tagName} />`,
type: 'success',
})
} catch (err) {
console.error('复制失败:', err)
message.open({
title: '复制失败',
type: 'error',
})
}
}}
>
{tagName}
)
}, [])
return (
<>
{icons.map((typeItem) => (
{typeItem.title}
{typeItem.children.map(renderIcon)}
))}
>
)
}
```
### 方向
```tsx
import React from 'react'
import * as Icons from '@hi-ui/icons'
import message from '@hi-ui/message'
export const Direction = () => {
const icons = React.useMemo(() => {
return [
{
id: 'filled',
title: '面型',
children: [
{ component: Icons.CaretDownFilled, tagName: 'CaretDownFilled' },
{ component: Icons.CaretLeftFilled, tagName: 'CaretLeftFilled' },
{ component: Icons.CaretRightFilled, tagName: 'CaretRightFilled' },
{ component: Icons.CaretUpFilled, tagName: 'CaretUpFilled' },
{ component: Icons.DragFilled, tagName: 'DragFilled' },
{ component: Icons.SortFilled, tagName: 'SortFilled' },
],
},
{
id: 'outlined',
title: '线型',
children: [
{ component: Icons.ArrowDownBoldOutlined, tagName: 'ArrowDownBoldOutlined' },
{ component: Icons.ArrowDownOutlined, tagName: 'ArrowDownOutlined' },
{ component: Icons.ArrowLeftBoldOutlined, tagName: 'ArrowLeftBoldOutlined' },
{ component: Icons.ArrowLeftOutlined, tagName: 'ArrowLeftOutlined' },
{ component: Icons.ArrowRightBoldOutlined, tagName: 'ArrowRightBoldOutlined' },
{ component: Icons.ArrowRightOutlined, tagName: 'ArrowRightOutlined' },
{ component: Icons.ArrowUpBoldOutlined, tagName: 'ArrowUpBoldOutlined' },
{ component: Icons.ArrowUpOutlined, tagName: 'ArrowUpOutlined' },
{ component: Icons.DirectionDownBoldOutlined, tagName: 'DirectionDownBoldOutlined' },
{ component: Icons.DirectionDownOutlined, tagName: 'DirectionDownOutlined' },
{ component: Icons.DirectionLeftBoldOutlined, tagName: 'DirectionLeftBoldOutlined' },
{ component: Icons.DirectionLeftOutlined, tagName: 'DirectionLeftOutlined' },
{ component: Icons.DirectionRightBoldOutlined, tagName: 'DirectionRightBoldOutlined' },
{ component: Icons.DirectionRightOutlined, tagName: 'DirectionRightOutlined' },
{ component: Icons.DirectionUpBoldOutlined, tagName: 'DirectionUpBoldOutlined' },
{ component: Icons.DirectionUpOutlined, tagName: 'DirectionUpOutlined' },
{ component: Icons.DownBoldOutlined, tagName: 'DownBoldOutlined' },
{ component: Icons.DownOutlined, tagName: 'DownOutlined' },
{ component: Icons.DownShortBoldOutlined, tagName: 'DownShortBoldOutlined' },
{ component: Icons.DownShortOutlined, tagName: 'DownShortOutlined' },
{ component: Icons.ExpandOutlined, tagName: 'ExpandOutlined' },
{ component: Icons.FullscreenExitOutlined, tagName: 'FullscreenExitOutlined' },
{ component: Icons.FullscreenOutlined, tagName: 'FullscreenOutlined' },
{ component: Icons.LeftBoldOutlined, tagName: 'LeftBoldOutlined' },
{ component: Icons.LeftOutlined, tagName: 'LeftOutlined' },
{ component: Icons.LeftRightOutlined, tagName: 'LeftRightOutlined' },
{ component: Icons.LeftShortBoldOutlined, tagName: 'LeftShortBoldOutlined' },
{ component: Icons.LeftShortOutlined, tagName: 'LeftShortOutlined' },
{ component: Icons.MenuFoldOutlined, tagName: 'MenuFoldOutlined' },
{ component: Icons.MenuUnfoldOutlined, tagName: 'MenuUnfoldOutlined' },
{ component: Icons.RightBoldOutlined, tagName: 'RightBoldOutlined' },
{ component: Icons.RightOutlined, tagName: 'RightOutlined' },
{ component: Icons.RightShortBoldOutlined, tagName: 'RightShortBoldOutlined' },
{ component: Icons.RightShortOutlined, tagName: 'RightShortOutlined' },
{ component: Icons.ShrinkOutlined, tagName: 'ShrinkOutlined' },
{ component: Icons.ToBottomOutlined, tagName: 'ToBottomOutlined' },
{ component: Icons.ToTopOutlined, tagName: 'ToTopOutlined' },
{ component: Icons.UpBoldOutlined, tagName: 'UpBoldOutlined' },
{ component: Icons.UpOutlined, tagName: 'UpOutlined' },
{ component: Icons.UpShortBoldOutlined, tagName: 'UpShortBoldOutlined' },
{ component: Icons.UpShortOutlined, tagName: 'UpShortOutlined' },
],
},
]
}, [])
const renderIcon = React.useCallback(({ component: Component, tagName }) => {
return (
{
evt.currentTarget.style.backgroundColor = '#f2f4f7'
evt.currentTarget.style.cursor = 'pointer'
}}
onMouseLeave={(evt) => {
evt.currentTarget.style.backgroundColor = 'transparent'
evt.currentTarget.style.cursor = 'default'
}}
onClick={() => {
try {
const textArea = document.createElement('textarea')
textArea.value = `<${tagName} />`
textArea.style.position = 'fixed'
textArea.style.opacity = '0'
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
message.open({
title: `复制成功:\n<${tagName} />`,
type: 'success',
})
} catch (err) {
console.error('复制失败:', err)
message.open({
title: '复制失败',
type: 'error',
})
}
}}
>
{tagName}
)
}, [])
return (
<>
{icons.map((typeItem) => (
{typeItem.title}
{typeItem.children.map(renderIcon)}
))}
>
)
}
```
### 编辑
```tsx
import React from 'react'
import * as Icons from '@hi-ui/icons'
import message from '@hi-ui/message'
export const Edit = () => {
const icons = React.useMemo(() => {
return [
{
id: 'filled',
title: '面型',
children: [
{ component: Icons.ClearFilled, tagName: 'ClearFilled' },
{ component: Icons.CopyFilled, tagName: 'CopyFilled' },
{ component: Icons.DeleteFilled, tagName: 'DeleteFilled' },
{ component: Icons.DetailsFilled, tagName: 'DetailsFilled' },
{ component: Icons.DuplicateFilled, tagName: 'DuplicateFilled' },
{ component: Icons.EditFilled, tagName: 'EditFilled' },
{ component: Icons.EllipsisCircleFilled, tagName: 'EllipsisCircleFilled' },
{ component: Icons.EmptyFilled, tagName: 'EmptyFilled' },
{ component: Icons.EqualProportionFilled, tagName: 'EqualProportionFilled' },
{ component: Icons.FilterFilled, tagName: 'FilterFilled' },
{ component: Icons.FolderAddFilled, tagName: 'FolderAddFilled' },
{ component: Icons.FolderMoveFilled, tagName: 'FolderMoveFilled' },
{ component: Icons.PasteFilled, tagName: 'PasteFilled' },
{ component: Icons.RotateLeftFilled, tagName: 'RotateLeftFilled' },
{ component: Icons.RotateRightFilled, tagName: 'RotateRightFilled' },
{ component: Icons.TableFilled, tagName: 'TableFilled' },
{ component: Icons.ZoomInFilled, tagName: 'ZoomInFilled' },
{ component: Icons.ZoomOutFilled, tagName: 'ZoomOutFilled' },
],
},
{
id: 'outlined',
title: '线型',
children: [
{ component: Icons.AverageOutlined, tagName: 'AverageOutlined' },
{ component: Icons.ClearOutlined, tagName: 'ClearOutlined' },
{ component: Icons.ColumnHeightOutlined, tagName: 'ColumnHeightOutlined' },
{ component: Icons.ColumnsOutlined, tagName: 'ColumnsOutlined' },
{ component: Icons.CopyOutlined, tagName: 'CopyOutlined' },
{ component: Icons.DeleteOutlined, tagName: 'DeleteOutlined' },
{ component: Icons.DetailsOutlined, tagName: 'DetailsOutlined' },
{ component: Icons.DocumentSearchOutlined, tagName: 'DocumentSearchOutlined' },
{ component: Icons.DragOutlined, tagName: 'DragOutlined' },
{ component: Icons.DuplicateOutlined, tagName: 'DuplicateOutlined' },
{ component: Icons.EditOutlined, tagName: 'EditOutlined' },
{ component: Icons.EllipsisCircleOutlined, tagName: 'EllipsisCircleOutlined' },
{ component: Icons.EllipsisOutlined, tagName: 'EllipsisOutlined' },
{ component: Icons.EllipsisVerticalOutlined, tagName: 'EllipsisVerticalOutlined' },
{ component: Icons.EmptyOutlined, tagName: 'EmptyOutlined' },
{ component: Icons.EqualProportionOutlined, tagName: 'EqualProportionOutlined' },
{ component: Icons.FilterOutlined, tagName: 'FilterOutlined' },
{ component: Icons.FolderAddOutlined, tagName: 'FolderAddOutlined' },
{ component: Icons.FolderMoveOutlined, tagName: 'FolderMoveOutlined' },
{ component: Icons.FreezeColumnOutlined, tagName: 'FreezeColumnOutlined' },
{ component: Icons.FrozenLineOutlined, tagName: 'FrozenLineOutlined' },
{ component: Icons.PasteOutlined, tagName: 'PasteOutlined' },
{ component: Icons.RotateLeftOutlined, tagName: 'RotateLeftOutlined' },
{ component: Icons.RotateRightOutlined, tagName: 'RotateRightOutlined' },
{ component: Icons.SaveOutlined, tagName: 'SaveOutlined' },
{ component: Icons.ScissorOutlined, tagName: 'ScissorOutlined' },
{ component: Icons.SortAscendingOutlined, tagName: 'SortAscendingOutlined' },
{ component: Icons.SortDescendingOutlined, tagName: 'SortDescendingOutlined' },
{ component: Icons.SummationOutlined, tagName: 'SummationOutlined' },
{ component: Icons.TableOutlined, tagName: 'TableOutlined' },
{ component: Icons.ZoomInOutlined, tagName: 'ZoomInOutlined' },
{ component: Icons.ZoomOutOutlined, tagName: 'ZoomOutOutlined' },
],
},
]
}, [])
const renderIcon = React.useCallback(({ component: Component, tagName }) => {
return (
{
evt.currentTarget.style.backgroundColor = '#f2f4f7'
evt.currentTarget.style.cursor = 'pointer'
}}
onMouseLeave={(evt) => {
evt.currentTarget.style.backgroundColor = 'transparent'
evt.currentTarget.style.cursor = 'default'
}}
onClick={() => {
try {
const textArea = document.createElement('textarea')
textArea.value = `<${tagName} />`
textArea.style.position = 'fixed'
textArea.style.opacity = '0'
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
message.open({
title: `复制成功:\n<${tagName} />`,
type: 'success',
})
} catch (err) {
console.error('复制失败:', err)
message.open({
title: '复制失败',
type: 'error',
})
}
}}
>
{tagName}
)
}, [])
return (
<>
{icons.map((typeItem) => (
{typeItem.title}
{typeItem.children.map(renderIcon)}
))}
>
)
}
```
### 文件
```tsx
import React from 'react'
import * as Icons from '@hi-ui/icons'
import message from '@hi-ui/message'
export const File = () => {
const icons = React.useMemo(() => {
return [
{
id: 'filled',
title: '面型',
children: [
{ component: Icons.FileFilled, tagName: 'FileFilled' },
{ component: Icons.FileExcelFilled, tagName: 'FileExcelFilled' },
{ component: Icons.FileExeFilled, tagName: 'FileExeFilled' },
{ component: Icons.FileJpgFilled, tagName: 'FileJpgFilled' },
{ component: Icons.FileKeynoteFilled, tagName: 'FileKeynoteFilled' },
{ component: Icons.FileMusicFilled, tagName: 'FileMusicFilled' },
{ component: Icons.FilePdfFilled, tagName: 'FilePdfFilled' },
{ component: Icons.FilePptFilled, tagName: 'FilePptFilled' },
{ component: Icons.FileQuestionFilled, tagName: 'FileQuestionFilled' },
{ component: Icons.FileTxtFilled, tagName: 'FileTxtFilled' },
{ component: Icons.FileVideoFilled, tagName: 'FileVideoFilled' },
{ component: Icons.FileWordFilled, tagName: 'FileWordFilled' },
{ component: Icons.FileZipFilled, tagName: 'FileZipFilled' },
],
},
{
id: 'outlined',
title: '线型',
children: [
{ component: Icons.FileOutlined, tagName: 'FileOutlined' },
{ component: Icons.FileExcelOutlined, tagName: 'FileExcelOutlined' },
{ component: Icons.FileExeOutlined, tagName: 'FileExeOutlined' },
{ component: Icons.FileJpgOutlined, tagName: 'FileJpgOutlined' },
{ component: Icons.FileKeynoteOutlined, tagName: 'FileKeynoteOutlined' },
{ component: Icons.FileMusicOutlined, tagName: 'FileMusicOutlined' },
{ component: Icons.FilePdfOutlined, tagName: 'FilePdfOutlined' },
{ component: Icons.FilePptOutlined, tagName: 'FilePptOutlined' },
{ component: Icons.FileQuestionOutlined, tagName: 'FileQuestionOutlined' },
{ component: Icons.FileTxtOutlined, tagName: 'FileTxtOutlined' },
{ component: Icons.FileVideoOutlined, tagName: 'FileVideoOutlined' },
{ component: Icons.FileWordOutlined, tagName: 'FileWordOutlined' },
{ component: Icons.FileZipOutlined, tagName: 'FileZipOutlined' },
],
},
{
id: 'colorful',
title: '多色型',
children: [
{ component: Icons.ExcelColorful, tagName: 'ExcelColorful' },
{ component: Icons.ExeColorful, tagName: 'ExeColorful' },
{ component: Icons.JpgColorful, tagName: 'JpgColorful' },
{ component: Icons.MusicColorful, tagName: 'MusicColorful' },
{ component: Icons.PdfColorful, tagName: 'PdfColorful' },
{ component: Icons.PptColorful, tagName: 'PptColorful' },
{ component: Icons.QuestionColorful, tagName: 'QuestionColorful' },
{ component: Icons.WordColorful, tagName: 'WordColorful' },
{ component: Icons.ZipColorful, tagName: 'ZipColorful' },
],
},
]
}, [])
const renderIcon = React.useCallback(({ component: Component, tagName }) => {
return (
{
evt.currentTarget.style.backgroundColor = '#f2f4f7'
evt.currentTarget.style.cursor = 'pointer'
}}
onMouseLeave={(evt) => {
evt.currentTarget.style.backgroundColor = 'transparent'
evt.currentTarget.style.cursor = 'default'
}}
onClick={() => {
try {
const textArea = document.createElement('textarea')
textArea.value = `<${tagName} />`
textArea.style.position = 'fixed'
textArea.style.opacity = '0'
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
message.open({
title: `复制成功:\n<${tagName} />`,
type: 'success',
})
} catch (err) {
console.error('复制失败:', err)
message.open({
title: '复制失败',
type: 'error',
})
}
}}
>
{tagName}
)
}, [])
return (
<>
{icons.map((typeItem) => (
{typeItem.title}
{typeItem.children.map(renderIcon)}
))}
>
)
}
```
### 数据
```tsx
import React from 'react'
import * as Icons from '@hi-ui/icons'
import message from '@hi-ui/message'
export const Data = () => {
const icons = React.useMemo(() => {
return [
{
id: 'filled',
title: '面型',
children: [
{ component: Icons.BarChartFilled, tagName: 'BarChartFilled' },
{ component: Icons.PieChartFilled, tagName: 'PieChartFilled' },
{ component: Icons.StockChartFilled, tagName: 'StockChartFilled' },
],
},
{
id: 'outlined',
title: '线型',
children: [
{ component: Icons.BarChartOutlined, tagName: 'BarChartOutlined' },
{ component: Icons.LineChartOutlined, tagName: 'LineChartOutlined' },
{ component: Icons.PieChartOutlined, tagName: 'PieChartOutlined' },
{ component: Icons.StockChartOutlined, tagName: 'StockChartOutlined' },
],
},
]
}, [])
const renderIcon = React.useCallback(({ component: Component, tagName }) => {
return (
{
evt.currentTarget.style.backgroundColor = '#f2f4f7'
evt.currentTarget.style.cursor = 'pointer'
}}
onMouseLeave={(evt) => {
evt.currentTarget.style.backgroundColor = 'transparent'
evt.currentTarget.style.cursor = 'default'
}}
onClick={() => {
try {
const textArea = document.createElement('textarea')
textArea.value = `<${tagName} />`
textArea.style.position = 'fixed'
textArea.style.opacity = '0'
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
message.open({
title: `复制成功:\n<${tagName} />`,
type: 'success',
})
} catch (err) {
console.error('复制失败:', err)
message.open({
title: '复制失败',
type: 'error',
})
}
}}
>
{tagName}
)
}, [])
return (
<>
{icons.map((typeItem) => (
{typeItem.title}
{typeItem.children.map(renderIcon)}
))}
>
)
}
```
## Props
### IconProps
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---- | --------------------- | ------ | ------ | ------ |
| size | 设置 Icon 的 尺寸大小 | number | - | - |
# Alert 警告提示
作用于页面的内容区域的提示,非触发类信息
## 使用示例
### 基础用法
根据用户的操作进行页面级或模块、区块级的提示
```tsx
import React from 'react'
import Alert from '@hi-ui/alert'
export const Basic = () => {
return (
<>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
>
)
}
```
### 带内容
反馈给用户的信息较多,需要用户阅读更详细
```tsx
import React from 'react'
import Alert from '@hi-ui/alert'
import Button from '@hi-ui/button'
export const Content = () => {
return (
<>
}
onClose={() => {
console.log('alert关闭回调')
}}
/>
文字说明文字说明文字说明
}
onClose={() => {
console.log('alert关闭回调')
}}
/>
文字说明文字说明文字说明
}
onClose={() => {
console.log('alert关闭回调')
}}
/>
文字说明文字说明文字说明
}
onClose={() => {
console.log('alert关闭回调')
}}
/>
>
)
}
```
### 不可关闭
反馈信息较为重要,需要引导用户阅读或关注
```tsx
import React from 'react'
import Alert from '@hi-ui/alert'
export const Closable = () => {
return (
<>
>
)
}
```
### 倒计时自动关闭
倒计时自动关闭反馈信息在出现一定时间后自动关闭,不打扰。注:最大值不能超过 2^31-1
```tsx
import React from 'react'
import Alert from '@hi-ui/alert'
export const Duration = () => {
return (
<>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
>
)
}
```
### Banner 公告
```tsx
import React from 'react'
import Alert from '@hi-ui/alert'
export const Banner = () => {
return (
<>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
{
console.log('alert关闭回调')
}}
/>
>
)
}
```
### 自定义关闭按钮
```tsx
import React from 'react'
import Alert from '@hi-ui/alert'
export const CloseIcon = () => {
return (
<>
Close}
onClose={() => {
console.log('alert关闭回调')
}}
/>
>
)
}
```
### 轮播通知
```tsx
import React from 'react'
import { TextLoop } from 'react-text-loop-next'
import Marquee from 'react-fast-marquee'
import Alert from '@hi-ui/alert'
export const Carousel = () => {
return (
<>
蒹葭苍苍,白露为霜。
所谓伊人,在水一方。
溯洄从之,道阻且长。
溯游从之,宛在水中央。
蒹葭凄凄,白露未晞。
}
/>
所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。蒹葭采采,白露未已。
}
/>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import Alert from '@hi-ui/alert'
import Button from '@hi-ui/button'
export const Size = () => {
return (
<>
lg
{
console.log('alert关闭回调')
}}
/>
文字说明文字说明文字说明
}
onClose={() => {
console.log('alert关闭回调')
}}
/>
md
{
console.log('alert关闭回调')
}}
/>
文字说明文字说明文字说明
}
onClose={() => {
console.log('alert关闭回调')
}}
/>
sm
{
console.log('alert关闭回调')
}}
/>
文字说明文字说明文字说明
}
onClose={() => {
console.log('alert关闭回调')
}}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Alert from '@hi-ui/alert'
export const Semantic = () => {
const [selected, setSelected] = useState<
'root' | 'icon' | 'message' | 'title' | 'content' | 'close'
>()
return (
<>
}
/>
{
return (
{
setSelected(dataItem.title as any)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Alert Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------ | ------------------------ | --------------------------- | ----------------------------------------------- | ------------------ |
| type | 警告提示类型 | AlertTypeEnum | "primary" \| "warning" \| "danger" \| "success" | "primary" |
| title *(required)* | 警告提示标题 | ReactNode | - | - |
| content | 警告提示内容 | ReactNode | - | - |
| closeable | 是否可关闭 | boolean | true \| false | true |
| duration | 自动关闭时间,单位为毫秒 | number | - | -1 |
| onClose | 关闭事件触发时的回调 | (() => void) | - | - |
| closeIcon | 自定义关闭 Icon | ReactNode | - | \ |
| showIcon | 是否显示提示图标 | boolean | true \| false | true |
| size | 设置尺寸 | Omit\ | Omit\ | - |
| classNames | | AlertSemanticClassNames | - | - |
| styles | | AlertSemanticStyles | - | - |
# Anchor 锚点
通过锚点可快速找到信息内容在当前页面的位置。
## 使用示例
### 基础用法
通过滚动或点击触发锚点节点的切换,需要注意 href 设置的是元素的 id 属性 `#id`
```tsx
import React from 'react'
import Anchor, { AnchorItem } from '@hi-ui/anchor'
export const Basic = () => {
const [containerElement, setContainerElement] = React.useState(null)
const scrollAreaNode = (
Scroll Area
)
return (
<>
容器化部署
{scrollAreaNode}
主要优点
{scrollAreaNode}
部署前准备
{scrollAreaNode}
发布模拟
{scrollAreaNode}
其它部署方式
{scrollAreaNode}
>
)
}
```
### 设置滚动偏移量
通过 `offset` 指定锚点节点触发的滚动偏移量,负值表示提前触发
```tsx
import React from 'react'
import Anchor, { AnchorItem } from '@hi-ui/anchor'
export const Offset = () => {
const [containerElement, setContainerElement] = React.useState(null)
const scrollAreaNode = (
Scroll Area
)
return (
<>
容器化部署
{scrollAreaNode}
主要优点
{scrollAreaNode}
部署前准备
{scrollAreaNode}
发布模拟
{scrollAreaNode}
其它部署方式
{scrollAreaNode}
>
)
}
```
### 多级树形锚点
作为 `AnchorItem` 的子节点传入,扩展树形锚点的层级
```tsx
import React from 'react'
import Anchor, { AnchorItem } from '@hi-ui/anchor'
export const Children = () => {
const [containerElement, setContainerElement] = React.useState(null)
const scrollAreaNode = (
Scroll Area
)
return (
<>
容器化部署
{scrollAreaNode}
主要优点
{scrollAreaNode}
部署前准备
{scrollAreaNode}
申请部署空间
{scrollAreaNode}
CI变量配置
发布模拟
{scrollAreaNode}
>
)
}
```
### 文本溢出
锚点文字不建议太长,超出会溢出展示
```tsx
import React from 'react'
import Anchor, { AnchorItem } from '@hi-ui/anchor'
export const Overflow = () => {
const [containerElement, setContainerElement] = React.useState(null)
const scrollAreaNode = (
Scroll Area
)
return (
<>
一级目录1号
{scrollAreaNode}
一级目录2号
{scrollAreaNode}
一级目录3号
{scrollAreaNode}
一级目录4号字数较多字数较多
{scrollAreaNode}
一级目录5号
{scrollAreaNode}
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Anchor, { AnchorItem } from '@hi-ui/anchor'
export const Semantic = () => {
const [selectedAnchor, setSelectedAnchor] = useState<'root' | 'list' | 'ink' | 'link'>()
const [selectedAnchorItem, setSelectedAnchorItem] = useState<'root' | 'link'>()
const [containerElement, setContainerElement] = React.useState(null)
const scrollAreaNode = (
Scroll Area
)
return (
<>
容器化部署
{scrollAreaNode}
主要优点
{scrollAreaNode}
部署前准备
{scrollAreaNode}
发布模拟
{scrollAreaNode}
其它部署方式
{scrollAreaNode}
Anchor
{
return (
{
setSelectedAnchor(dataItem.title as any)
}}
onMouseLeave={() => {
setSelectedAnchor(undefined)
}}
>
)
}}
/>
AnchorItem
{
return (
{
setSelectedAnchorItem(dataItem.title as any)
}}
onMouseLeave={() => {
setSelectedAnchorItem(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Anchor Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | ---------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------ | ------ |
| container | 指定触发滚动的容器 | HTMLElement \| (() => HTMLElement \| null) \| null | null \| HTMLElement \| () => HTMLElement \| null | - |
| offset | 滚动至距离目标锚点位置指定的偏移量 \`offset\` 时触发 | number | - | - |
| onChange | 锚点切换时触发 | ((href: string) => void) | - | - |
| classNames | | AnchorSemanticClassNames | - | - |
| styles | | AnchorSemanticStyles | - | - |
### AnchorItem Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | ----------------------------------------------------------------------------------------- | ---------------------------- | ------ | ------ |
| title | 锚点项标题内容 | ReactNode | - | - |
| children | 下一级锚点节点列表,可传入 \`AnchorItem\` | ReactNode | - | - |
| href | 设置锚点的跳转链接 | string | - | - |
| offset | 滚动至距离目标锚点位置指定的偏移量 \`offset\` 时触发,优先级高于 \`AnchorProps\` 中的设置 | number | - | - |
| classNames | | AnchorItemSemanticClassNames | - | - |
| styles | | AnchorItemSemanticStyles | - | - |
# Avatar 头像
用来代表用户或事物,支持图片、图标或字符展示。
## 使用示例
### 基础用法
提供基础的默认头像
```tsx
import React from 'react'
import Avatar from '@hi-ui/avatar'
export const Basic = () => {
return (
<>
>
)
}
```
### 不同内容
支持在头像容器中放置不同的内容元素
```tsx
import React from 'react'
import Avatar from '@hi-ui/avatar'
import { EditOutlined, PlusOutlined } from '@hi-ui/icons'
export const Content = () => {
return (
<>
} />
>
)
}
```
### 不同形状
通过 shape 指定头像的形状
```tsx
import React from 'react'
import Avatar from '@hi-ui/avatar'
export const Shape = () => {
return (
<>
>
)
}
```
### 不同尺寸
默认支持 5 种头像标准尺寸,通过 size 设置
```tsx
import React from 'react'
import Avatar from '@hi-ui/avatar'
export const Size = () => {
return (
<>
>
)
}
```
### 自定义尺寸
通过 size 传入数值自定义头像大小
```tsx
import React from 'react'
import Avatar from '@hi-ui/avatar'
export const CustomSize = () => {
return (
<>
>
)
}
```
### 自定义颜色
设置 style 自定义头像的背景色
```tsx
import React from 'react'
import Avatar from '@hi-ui/avatar'
export const CustomColor = () => {
return (
<>
>
)
}
```
### 头像组
通过 AvatarGroup 包裹多个 Avatar 组件,可以实现头像组的效果
```tsx
import React from 'react'
import { EllipsisOutlined } from '@hi-ui/icons'
import Avatar from '@hi-ui/avatar'
export const Group = () => {
return (
<>
基本用法
配置更多按钮
,
// style: { backgroundColor: '#74a2ff', color: '#fff' },
}}
>
配置更多头像弹窗
自定义更多头像展示方式 ,
style: { maxWidth: 420 },
}}
>
>
)
}
```
## Props
### Avatar Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ------------------------------------- | ------------------------------------ | ---------------------------------------------- | -------- |
| size | 头像尺寸 | number \| AvatarSizeEnum | number \| "xs" \| "sm" \| "md" \| "lg" \| "xl" | - |
| initials | 头像缩写字母 | ReactNode | - | - |
| shape | 设置形状 | "circle" \| "square" | "circle" \| "square" | "circle" |
| src | 头像 url | string | - | - |
| name | 头像名,用于语义化设置 | string | - | - |
| icon | 设置按钮图标 | ReactNode | - | - |
| srcSet | 针对 img 不同的屏幕分辨率来源地址设置 | string | - | - |
| onError | 针对 img 加载失败回调 | ReactEventHandler\ | - | - |
| bordered | 是否带边框 | boolean | true \| false | false |
# BackTop 回到顶部
当内容滑动到设定高度时,显示回到顶部按钮,点击按钮回到最顶部。
## 使用示例
### 基础用法
当滚动到设定高度时,会出现回到顶部按钮,点击回到最顶部
```tsx
import React from 'react'
import Tooltip from '@hi-ui/tooltip'
import { UpShortOutlined } from '@hi-ui/icons'
import BackTop from '@hi-ui/back-top'
export const Basic = () => {
return (
<>
document.getElementById('back-top_target')}
/>
{Array.from({ length: 10 }, (_, index) => (
页面内容{index}
))}
>
)
}
```
### 参数设置
设置按钮形状、主题、滚动时间、滚动到多高时显示
```tsx
import React, { useState } from 'react'
import Space from '@hi-ui/space'
import Select from '@hi-ui/select'
import Input from '@hi-ui/input'
import BackTop from '@hi-ui/back-top'
export const Settings = () => {
const [shape, setShape] = useState('circle')
const [duration, setDuration] = useState(400)
const [visibleHeight, setVisibleHeight] = useState(400)
return (
<>
>
)
}
```
### 自定义按钮位置和内容
给组件传入样式和children
```tsx
import React from 'react'
import Tooltip from '@hi-ui/tooltip'
import { ToTopOutlined } from '@hi-ui/icons'
import BackTop from '@hi-ui/back-top'
export const Custom = () => {
return (
<>
document.getElementById('back-top_custom')}
onClick={() => {
Tooltip.close('back-top-custom')
}}
onMouseEnter={(evt) => {
Tooltip.open(evt.currentTarget, {
key: 'back-top-custom',
title: '回到顶部',
placement: 'left',
})
}}
onMouseLeave={() => {
Tooltip.close('back-top-custom')
}}
>
{Array.from({ length: 10 }, (_, index) => (
页面内容{index}
))}
>
)
}
```
### 组合使用
和其他元素组合使用
```tsx
import React from 'react'
import { ScanOutlined, MessageOutlined } from '@hi-ui/icons'
import BackTop from '@hi-ui/back-top'
export const Compose = () => {
return (
<>
document.getElementById('back-top_compose')}
/>
{Array.from({ length: 10 }, (_, index) => (
页面内容{index}
))}
>
)
}
```
## Props
### BackTop Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------- | ------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------ | -------- |
| shape | 设置形状 | "circle" \| "square" | "circle" \| "square" | "circle" |
| visibleHeight | 当内容滚动到该高度时,显示回到顶部组件 | number | - | 400 |
| duration | 回到顶部所需时间(ms) | number | - | 400 |
| container | 设置需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 | HTMLElement \| (() => HTMLElement \| null) \| null | null \| HTMLElement \| () => HTMLElement \| null | - |
| onClick | 点击回到顶部时的回调函数 | (() => void) | - | - |
# Badge 红点 / 徽标
红点用来展示新消息的提示,徽标用于展示消息的数量、提示
## 使用示例
### 基础用法
标识是否有新消息
```tsx
import React from 'react'
import Badge from '@hi-ui/badge'
import { Button } from '@hi-ui/button'
import { BellOutlined } from '@hi-ui/icons'
export const Basic = () => {
return (
<>
>
)
}
```
### 自定义角标内容
```tsx
import React from 'react'
import Badge from '@hi-ui/badge'
import { Button } from '@hi-ui/button'
import { BellFilled } from '@hi-ui/icons'
export const Custom = () => {
return (
<>
}>
} />
>
)
}
```
### 徽标
标识消息数或简洁描述
```tsx
import React from 'react'
import Badge from '@hi-ui/badge'
import { BellOutlined } from '@hi-ui/icons'
export const Bubble = () => {
return (
<>
>
)
}
```
### 数值显示上限
```tsx
import React from 'react'
import Badge from '@hi-ui/badge'
import { Avatar } from '@hi-ui/avatar'
export const Max = () => {
return (
<>
>
)
}
```
### 独立使用
```tsx
import React from 'react'
import Badge from '@hi-ui/badge'
export const Independent = () => {
return (
<>
>
)
}
```
### 位置偏移
```tsx
import React from 'react'
import Badge from '@hi-ui/badge'
import { Button } from '@hi-ui/button'
export const Offset = () => {
return (
<>
>
)
}
```
### 自定义颜色
```tsx
import React from 'react'
import { Button } from '@hi-ui/button'
import Badge from '@hi-ui/badge'
export const Color = () => {
const colors = [
'red',
'yellow',
'pink',
'orange',
'cyan',
'blue',
'green',
'purple',
'magenta',
'#2db7f5',
'#108ee9',
]
return (
<>
{colors.map((color) => (
))}
>
)
}
```
## Props
### Badge Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------- | ---------------------------------------- | ---------------------------- | ----------------- | -------- |
| content | 气泡显示内容 | ReactNode | - | - |
| type | 气泡显示的形态,可选带文字的气泡或小红点 | BadgeTypeEnum | "dot" \| "bubble" | "bubble" |
| max | 气泡显示的最大值,超过值用'+'号替代 | number | - | 99 |
| visible | 是否显示气泡 | boolean | true \| false | true |
| color | 气泡颜色 | string | - | - |
| offset | 设置状态点的位置偏移 | \[left: number, top: number] | - | - |
# Breadcrumb 面包屑
一种特殊的导航,用来指引在系统中用户的行踪和方向
## 使用示例
### 基础用法
明确访问路径的每一个节点
```tsx
import React from 'react'
import Breadcrumb from '@hi-ui/breadcrumb'
export const Basic = () => {
const [data] = React.useState([
{
title: '首页',
href: '/home',
},
{
title: '列表',
href: '/list',
},
{
title: '手机详情',
href: '/phone',
},
])
return (
<>
{
console.log('get item: ', item)
}}
/>
>
)
}
```
### 不同尺寸
通过 size 设置不同大小的面包屑
```tsx
import React from 'react'
import Breadcrumb from '@hi-ui/breadcrumb'
export const Size = () => {
const [data] = React.useState([
{
title: '首页',
href: '/home',
},
{
title: '列表',
href: '/list',
},
{
title: '手机详情',
href: '/phone',
},
])
return (
<>
{
console.log('get item: ', item)
}}
/>
{
console.log('get item: ', item)
}}
/>
>
)
}
```
### 前缀图标
```tsx
import React from 'react'
import Breadcrumb from '@hi-ui/breadcrumb'
import { HomeOutlined } from '@hi-ui/icons'
export const CustomIcon = () => {
const [data] = React.useState([
{
icon: ,
title: '首页',
href: '/home',
},
{
icon: ,
title: '列表',
href: '/list',
},
{
icon: ,
title: '手机详情',
href: '/phone',
},
])
return (
<>
{
console.log('get item: ', item)
}}
/>
>
)
}
```
### 自定义分隔符
```tsx
import { RightOutlined } from '@hi-ui/icons'
import React from 'react'
import Breadcrumb from '@hi-ui/breadcrumb'
export const Separator = () => {
const [data] = React.useState([
{
title: '首页',
href: '/home',
},
{
title: '列表',
href: '/list',
},
{
title: '手机详情',
href: '/phone',
},
])
return (
<>
{
console.log('get item: ', item)
}}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import { HomeOutlined } from '@hi-ui/icons'
import Breadcrumb from '@hi-ui/breadcrumb'
export const Semantic = () => {
const [selected, setSelected] = useState<'root' | 'item' | 'content' | 'icon' | 'separator'>()
const [data] = React.useState([
{
icon: ,
title: '首页',
href: '/home',
},
{
icon: ,
title: '列表',
href: '/list',
},
{
icon: ,
title: '手机详情',
href: '/phone',
},
])
return (
<>
{
return (
{
setSelected(dataItem.title as any)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Breadcrumb Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------ | ------------------ |
| separator | 面包屑分隔符 | ReactNode | - | \ |
| data | 面包屑数据项 | BreadcrumbDataItem\[] | - | - |
| fieldNames | 设置 data 中 title, href, target, icon 对应的 key | HiBaseFieldNames | - | - |
| size | 面包屑尺寸 | BreadcrumbSizeEnum | "sm" \| "md" | - |
| onClick | 点击事件 | ((evt: MouseEvent\, item: BreadcrumbDataItem, index: number) => void) | - | - |
| classNames | | BreadcrumbSemanticClassNames | - | - |
| styles | | BreadcrumbSemanticStyles | - | - |
## Type
### BreadcrumbDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------ | --------------------------------------------- | --------- | ----------------------------------------------- | ------ |
| title | 面包屑的标题 | ReactNode | - | - |
| href | 设置按钮链接,设置后将用 a 标签渲染按钮 | string | ︎ | - |
| target | 同 a 标签的 target 属性,仅在设置 href 后有效 | string | ︎'\_self' \| '\_blank' \| '\_parent' \| '\_top' | - |
| icon | 自定义图标 | ReactNode | ︎ | - |
# Button 按钮
引导用户去触发操作的区域
## 使用示例
### 基础用法
```tsx
import React from 'react'
import Button from '@hi-ui/button'
export const Basic = () => {
return (
<>
>
)
}
```
### 不同外观
```tsx
import React from 'react'
import Space from '@hi-ui/space'
import Button from '@hi-ui/button'
export const Appearance = () => {
return (
<>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import { PlusOutlined } from '@hi-ui/icons'
export const Size = () => {
return (
<>
} size="xs" />
} size="sm" />
} />
} size="lg" />
} size="xs" />
} size="sm" />
} />
} size="lg" />
} size="xs" />
} size="sm" />
} />
} size="lg" />
} size="xs" />
} size="sm" />
} />
} size="lg" />
} size="xs" />
} size="sm" />
} />
} size="lg" />
>
)
}
```
### 带图标
图标能够明确表达按钮的动作含义,成组使用,与文字搭配,突出按钮的重要性
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import { PlusOutlined, MinusOutlined } from '@hi-ui/icons'
export const Icon = () => {
return (
<>
, ]}>
Solid
} />
]}>Solid
} />
}>
Solid
} />
}>
Solid
} />
, ]}
>
Filled
} />
]}>
Solid
} />
}>
Filled
} />
}>
Filled
} />
, ]}
appearance="line"
>
Line
} appearance="line" />
]} appearance="line">
Line
} appearance="line" />
} appearance="line">
Line
} appearance="line" />
} appearance="line">
Line
} appearance="line" />
, ]}
appearance="text"
>
Text
} appearance="text" />
]} appearance="text">
Text
} appearance="text" />
} appearance="text">
Text
} appearance="text" />
} appearance="text">
Text
} appearance="text" />
, ]}
appearance="link"
>
Link
} appearance="link" />
]} appearance="link">
Link
} appearance="link" />
} appearance="link">
Link
} appearance="link" />
} appearance="link">
Link
} appearance="link" />
>
)
}
```
### 加载中状态
请求服务器发生延迟时或缓冲状态,使用加载中进行状态说明
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import { PlusOutlined } from '@hi-ui/icons'
export const Loading = () => {
return (
<>
} loading>
Solid
} loading />
} loading>
Solid
} loading />
} loading>
Solid
} loading />
} loading>
Solid
} loading />
} loading>
Filled
} loading />
} loading>
Filled
} loading />
} loading>
Filled
} loading />
} loading>
Filled
} loading />
} appearance="line" loading>
Line
} appearance="line" loading />
} appearance="line" loading>
Line
} appearance="line" loading />
} appearance="line" loading>
Line
} appearance="line" loading />
} appearance="line" loading>
Line
} appearance="line" loading />
} appearance="text" loading>
Text
} appearance="text" loading />
} appearance="text" loading>
Text
} appearance="text" loading />
} appearance="text" loading>
Text
} appearance="text" loading />
} appearance="text" loading>
Text
} appearance="text" loading />
} appearance="link" loading>
Link
} appearance="link" loading />
} appearance="link" loading>
Link
} appearance="link" loading />
} appearance="link" loading>
Link
} appearance="link" loading />
} appearance="link" loading>
Link
} appearance="link" loading />
>
)
}
```
### 禁用状态
暂不可操作的状态
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import { PlusOutlined } from '@hi-ui/icons'
export const Disabled = () => {
return (
<>
} disabled>
Solid
} appearance="filled" disabled>
Filled
} appearance="line" disabled>
Line
} appearance="text" disabled>
Text
} appearance="link" disabled>
Link
>
)
}
```
### 按钮组
用于将有并列关系的一组动作,以组的形式展示
```tsx
import React from 'react'
import { ButtonGroup, Button } from '@hi-ui/button'
import { EditOutlined } from '@hi-ui/icons'
export const Group = () => {
return (
<>
} />
} />
} />
} />
>
)
}
```
### 不同形状
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import { PlusOutlined } from '@hi-ui/icons'
export const Shape = () => {
const btnRef = React.useRef(null)
React.useEffect(() => {
console.log(btnRef)
}, [])
return (
<>
square
} size="xs" />
} size="sm" />
} />
} size="lg" />
round
} size="xs" />
} size="sm" />
} />
} size="lg" />
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Button from '@hi-ui/button'
import { PlusOutlined, MinusOutlined } from '@hi-ui/icons'
export const Semantic = () => {
const [selected, setSelected] = useState<'root' | 'prefixIcon' | 'suffixIcon'>()
return (
<>
普通用法
, ]}
classNames={{
root: 'my-button__root',
prefixIcon: 'my-button__prefix-icon',
suffixIcon: 'my-button__suffix-icon',
}}
styles={{
[selected as string]: {
outline: '1px solid #ffbe0a',
},
}}
>
按钮
{
return (
{
setSelected(dataItem.title as any)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
函数用法
}
classNames={(info) => {
if (info.props.type === 'primary') {
return {
root: 'my-button__root--primary',
prefixIcon: 'my-button__prefix-icon--primary',
}
}
return {}
}}
styles={(info) => {
if (info.props.type === 'primary') {
return {
root: {
borderRadius: 8,
},
prefixIcon: {
fontSize: 18,
},
}
}
return {}
}}
>
按钮
>
)
}
```
## Props
### Button Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | --------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| type | 设置按钮类型 | "primary" \| "success" \| "danger" \| "default" \| "secondary" | "primary" \| "success" \| "danger" \| "default" \| "secondary" | "default" |
| size | 设置按钮尺寸 | "xs" \| "sm" \| "md" \| "lg" | "xs" \| "sm" \| "md" \| "lg" | - |
| appearance | 设置按钮外观 | "link" \| "line" \| "text" \| "solid" \| "filled" | "link" \| "line" \| "text" \| "solid" \| "filled" | - |
| disabled | 设置按钮是否禁用 | boolean | true \| false | false |
| loading | 是否显示 loading | boolean | true \| false | false |
| href | 设置按钮链接,设置后将用 a 标签渲染按钮 | string | - | - |
| target | 同 a 标签的 target 属性,仅在设置 href 后有效 | "\_self" \| "\_blank" \| "\_parent" \| "\_top" | "\_self" \| "\_blank" \| "\_parent" \| "\_top" | - |
| icon | 设置按钮图标 | ReactNode \| ReactNode\[] | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| ReactNode\[] | null |
| shape | 设置按钮形状 | "square" \| "round" | "square" \| "round" | "square" |
| onClick | 点击按钮时的回调 | ((evt: MouseEvent\) => void) | - | - |
| classNames | | ButtonSemanticClassNames | - | - |
| styles | | ButtonSemanticStyles | - | - |
### ButtonGroup Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ------------------------------------ | --------- | ------ | ------ |
| children | 孩子节点,传入单个或多个 Button 组件 | ReactNode | - | - |
# Card 卡片
用来展示不同类型信息或信息组的轻量容器
## 使用示例
### 基础用法
用卡片封装独立的信息实体,如模块、功能、项目、应用等,或还原实际生活中的卡片应用
```tsx
import React from 'react'
import Card from '@hi-ui/card'
export const Basic = () => {
return (
<>
>
)
}
```
### 不同尺寸
为卡片定义了 2 种尺寸,根据页面的实际空间选用紧凑程度
```tsx
import Button from '@hi-ui/button'
import React from 'react'
import Card from '@hi-ui/card'
export const Size = () => {
return (
<>
紧凑
链接
}
>
此处展示卡片内容
常规
链接
}
>
此处展示卡片内容
大尺寸
链接
}
>
此处展示卡片内容
不同尺寸嵌套
此处展示卡片内容
>
)
}
```
### 带操作用法
可对卡片进行编辑、删除等操作
```tsx
import React from 'react'
import Card from '@hi-ui/card'
import Button from '@hi-ui/button'
export const Extra = () => {
return (
<>
链接
}
>
此处展示卡片内容
链接
}
>
此处展示卡片内容
>
)
}
```
### 带副标题
```tsx
import Button from '@hi-ui/button'
import React from 'react'
import Card from '@hi-ui/card'
export const Subtitle = () => {
return (
<>
链接
}
subtitle="这是一句简要的卡片副标题"
>
此处展示卡片内容
链接
}
subtitle="这是一句简要的卡片副标题"
>
此处展示卡片内容
>
)
}
```
### 无标题卡片
```tsx
import React from 'react'
import Card from '@hi-ui/card'
export const NoHeader = () => {
return (
<>
>
)
}
```
### 文本卡片
```tsx
import React from 'react'
import Card from '@hi-ui/card'
export const TextCard = () => {
return (
<>
标题
这里是辅助描述
这里是文字内容这里是文字内容这里是文字内容这里是文字内容这里是文字内容这里是文字内容这里是文字内容这里是文字内容这里是文字内容这里是文字内容这里是文字内容这里是文字内容
>
)
}
```
### 带头图
卡片中加入图片,增强识别性,常用于描述应用、项目等
```tsx
import React from 'react'
import Card from '@hi-ui/card'
export const Img = () => {
const [list] = React.useState(() => {
return new Array(6).fill({
image: 'http://i1.mifile.cn/f/i/hiui/docs/card/pic_9.png',
title: '此处展示商品名称',
content: '此处展示商品相关描述信息',
})
})
return (
<>
{list.map((item, index) => {
return (
{item.content}
)
})}
>
)
}
```
### 无边框
```tsx
import React from 'react'
import Card from '@hi-ui/card'
export const NoBordered = () => {
return (
<>
>
)
}
```
### hover 效果
```tsx
import React from 'react'
import Card from '@hi-ui/card'
export const Hoverable = () => {
return (
<>
>
)
}
```
### 加载中状态
```tsx
import React from 'react'
import Card from '@hi-ui/card'
export const Loading = () => {
return (
<>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Card from '@hi-ui/card'
import Button from '@hi-ui/button'
export const Semantic = () => {
const [selected, setSelected] = useState<
'root' | 'cover' | 'header' | 'head' | 'title' | 'extra' | 'subhead' | 'body'
>()
return (
<>
普通用法
操作}
style={{ width: '80%', overflow: 'unset' }}
classNames={{
root: 'my-card__root',
cover: 'my-card__cover',
header: 'my-card__header',
head: 'my-card__head',
title: 'my-card__title',
extra: 'my-card__extra',
subhead: 'my-card__subhead',
body: 'my-card__body',
}}
styles={{
[selected as string]: {
outline: '1px solid #ffbe0a',
},
}}
coverUrl="http://i1.mifile.cn/f/i/hiui/docs/card/pic_9.png"
>
卡片内容
{
return (
{
setSelected(dataItem.title as any)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
函数用法
操作}
classNames={(info) => {
if (info.props.hoverable) {
return {
root: 'my-card__root--hoverable',
header: 'my-card__header--hoverable',
}
}
return {}
}}
styles={(info) => {
if (info.props.hoverable) {
return {
root: {
borderRadius: 4,
},
}
}
return {}
}}
hoverable
>
卡片内容
>
)
}
```
## Props
### Card Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | -------------------------------- | ---------------------- | --------------------------- | ------ |
| title | 卡片标题 | ReactNode | - | - |
| bordered | 是否展示边框 | boolean | true \| false | true |
| loading | 是否展示加载状态 | boolean | true \| false | - |
| hoverable | 鼠标移入卡片时是否显示阴影 | boolean | true \| false | false |
| extra | 标题右侧的拓展区域 | ReactNode | - | - |
| cover | 卡片的封面 | ReactNode | - | - |
| coverUrl | 卡片的封面的图片链接 | string | - | - |
| size | 卡片的尺寸 | CardSizeEnum | Omit\ | - |
| showHeaderDivider | 是否展示卡片头部和内容区域分割线 | boolean | true \| false | - |
| children | 内容区域 | ReactNode | - | - |
| classNames | | CardSemanticClassNames | - | - |
| styles | | CardSemanticStyles | - | - |
# Carousel 走马灯
又叫图片轮播器,是用于在同一空间展示一组图片的容器。
## 使用示例
### 基础用法
```tsx
import React from 'react'
import Carousel from '@hi-ui/carousel'
export const Basic = () => {
const generateContent = () => {
return [

console.log('1')}
/>
Christmas
,
console.log('2')}
/>,
console.log('3')}
/>,
]
}
return (
<>
{generateContent()}
>
)
}
```
### 自定义宽高
```tsx
import React from 'react'
import Carousel from '@hi-ui/carousel'
export const Resize = () => {
const generateContent = () => {
return [

console.log('1')}
/>
Christmas
,
console.log('2')}
/>,
console.log('3')}
/>,
]
}
return (
<>
760 X 320
{generateContent()}
760 X 469
{generateContent()}
760 X 200
{generateContent()}
>
)
}
```
### 不同箭头尺寸
```tsx
import React from 'react'
import Carousel from '@hi-ui/carousel'
export const ArrowSize = () => {
const generateContent = () => {
return [

console.log('1')}
/>
Christmas
,
console.log('2')}
/>,
console.log('3')}
/>,
]
}
return (
<>
lg(large)
{generateContent()}
md(middle)
{generateContent()}
sm(small)
{generateContent()}
>
)
}
```
### 自动切换间隔
```tsx
import React from 'react'
import Carousel from '@hi-ui/carousel'
export const Duration = () => {
const generateContent = () => {
return [

console.log('1')}
/>
Christmas
,
console.log('2')}
/>,
console.log('3')}
/>,
]
}
return (
<>
0ms(default)(disabled)
{generateContent()}
5000ms
{generateContent()}
>
)
}
```
### 指示器类型
```tsx
import React from 'react'
import Carousel from '@hi-ui/carousel'
export const DotType = () => {
const generateContent = () => {
return [

console.log('1')}
/>
Christmas
,
console.log('2')}
/>,
console.log('3')}
/>,
]
}
return (
<>
line (default)
{generateContent()}
dot
{generateContent()}
>
)
}
```
### 指示器位置
```tsx
import React from 'react'
import Carousel from '@hi-ui/carousel'
export const dotPlacement = () => {
const generateContent = () => {
return [

console.log('1')}
/>
Christmas
,
console.log('2')}
/>,
console.log('3')}
/>,
]
}
return (
<>
bottom(default)
{generateContent()}
left
{generateContent()}
top
{generateContent()}
right
{generateContent()}
outer
{generateContent()}
>
)
}
```
### 显隐配置
```tsx
import React from 'react'
import Carousel from '@hi-ui/carousel'
export const Config = () => {
const generateContent = () => {
return [

console.log('1')}
/>
Christmas
,
console.log('2')}
/>,
console.log('3')}
/>,
]
}
return (
<>
showPages = true
{generateContent()}
showDot = false
{generateContent()}
showArrows = false
{generateContent()}
>
)
}
```
### 响应式
```tsx
import React from 'react'
import Carousel from '@hi-ui/carousel'
export const Responsive = () => {
const generateContent = () => {
return [

console.log('1')}
/>
Christmas
,
console.log('2')}
/>,
console.log('3')}
/>,
]
}
return (
<>
{generateContent()}
模拟侧边栏定宽
>
)
}
```
## Props
### Carousel Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------- | ------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------- | ---------- |
| duration | 自动切换间隔(0代表不用自动切换) | number | - | "0" |
| showDots | 是否展示分页指示器 | boolean | true \| false | "true" |
| showArrows | 是否展示箭头指示器 | boolean | true \| false | "true" |
| defaultActive | 默认激活索引(从0开始计算索引) | number | - | "0" |
| showPages | 是否展示页码指示器 | boolean | true \| false | "false" |
| arrowSize | 箭头指示器尺寸 | CarouselArrowSizeEnum | "lg" \| "md" \| "sm" | "'md'" |
| dotType | 分页指示器类型 | CarouselDotTypeEnum | "line" \| "slider" \| "dot" | "'slider'" |
| dotPlacement | 分页指示器位置 | CarouselDotPlacementEnum | "left" \| "right" \| "top" \| "bottom" \| "outer" | "'bottom'" |
| onIndexChange | index 变化时的回调函数 | ((index: number, evt: MouseEvent\) => void) | - | - |
# Cascader 级联选择
一种接收数据的容器,为用户提供选择一部分数据的能力
## 使用示例
### 基础用法
展示从多个收起的备选项中选出的一个选项
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const Basic = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
return (
<>
{
console.log('onChange', ...args)
}}
onItemClick={(...args) => {
console.log('onItemClick', ...args)
}}
>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const Size = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
return (
<>
xs
{
console.log('onChange', ...args)
}}
>
sm
{
console.log('onChange', ...args)
}}
>
md
{
console.log('onChange', ...args)
}}
>
lg
{
console.log('onChange', ...args)
}}
>
>
)
}
```
### 展现形式
设置展现形式
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const Appearance = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
return (
<>
Filled
{
console.log('onChange', ...args)
}}
>
Line
{
console.log('onChange', ...args)
}}
>
Unset
{
console.log('onChange', ...args)
}}
>
Borderless
{
console.log('onChange', ...args)
}}
>
Contained
{
console.log('onChange', ...args)
}}
>
>
)
}
```
### 禁用状态
暂不可操作的状态
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const Disabled = () => {
const [data] = React.useState([
{
id: '0',
title: '0',
children: [
{
id: '0-0',
title: '0-0',
children: [
{
id: '0-0-0',
title: '0-0-0',
},
{
id: '0-0-1',
title: '0-0-1',
},
{
id: '0-0-2',
title: '0-0-2',
},
],
},
{
id: '0-1',
title: '0-1',
children: [
{
id: '0-1-0',
title: '0-1-0',
},
{
id: '0-1-1',
title: '0-1-1',
},
],
},
{
id: '0-2',
title: '0-2',
disabled: true,
children: [
{
id: '0-2-0',
title: '0-2-0',
},
{
id: '0-2-1',
title: '0-2-1',
},
],
},
{
id: '0-3',
title: '0-3',
children: [
{
id: '0-3-0',
title: '0-3-0',
},
{
id: '0-3-1',
title: '0-3-1',
},
{
id: '0-3-2',
title: '0-3-2',
},
],
},
{
id: '0-4',
title: '0-4',
children: [
{
id: '0-4-0',
title: '0-4-0',
},
{
id: '0-4-1',
title: '0-4-1',
},
],
},
{
id: '0-5',
title: '0-5',
children: [
{
id: '0-5-0',
title: '0-5-0',
},
{
id: '0-5-1',
title: '0-5-1',
},
],
},
],
},
{
id: '1',
title: '1',
children: [
{
id: '1-0',
title: '1-0',
children: [
{
id: '1-0-0',
title: '1-0-0',
},
{
id: '1-0-1',
title: '1-0-1',
children: [
{
id: '1-0-1-0',
title: '1-0-1-0',
},
{
id: '1-0-1-1',
title: '1-0-1-1',
},
],
},
{
id: '1-0-2',
title: '1-0-2',
},
],
},
{
id: '1-1',
title: '1-1',
},
{
id: '1-2',
title: '1-2',
},
{
id: '1-3',
title: '1-3',
},
],
},
])
return (
<>
整体禁用
禁用某个选项
>
)
}
```
### 带搜索
选项数量较大,不熟悉数据的结构关系情况下,用搜索关键词的方式快速定位
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const Search = () => {
const [data] = React.useState([
{
id: 'up-1',
title: 'up',
children: [
{
id: 'up-1-0',
title: '小米',
children: [
{
id: 'up-1-0-0',
title: 'leaf',
},
],
},
{
id: 'up-1-1',
title: 'up-1-1',
},
],
},
{
id: '0',
title: 'up-0',
children: [
{
id: '0-0',
title: '0-0',
children: [
{
id: '0-0-0',
title: '0-0-0',
},
{
id: '0-0-1',
title: '0-0-1',
},
{
id: '0-0-2',
title: '0-0-2',
},
],
},
{
id: '0-1',
title: '0-1',
children: [
{
id: '0-1-0',
title: '0-1-0',
},
{
id: '0-1-1',
title: '0-1-1',
},
],
},
{
id: '0-2',
title: '0-2',
children: [
{
id: '0-2-0',
title: '0-2-0',
},
{
id: '0-2-1',
title: '0-2-1',
},
],
},
{
id: '0-3',
title: '0-3',
children: [
{
id: '0-3-0',
title: '0-3-0',
},
{
id: '0-3-1',
title: '0-3-1',
},
{
id: '0-3-2',
title: '0-3-2',
},
],
},
{
id: '0-4',
title: '0-4',
children: [
{
id: '0-4-0',
title: '0-4-0',
},
{
id: '0-4-1',
title: '0-4-1',
},
],
},
{
id: '0-5',
title: '0-5',
children: [
{
id: '0-5-0',
title: '0-5-0',
},
{
id: '0-5-1',
title: '0-5-1',
},
],
},
{
id: '0-6',
title: '0-6',
children: [
{
id: '0-6-0',
title: '0-6-0',
},
{
id: '0-6-1',
title: '0-6-1',
},
{
id: '0-6-2',
title: '0-6-2',
},
],
},
{
id: '0-7',
title: '0-7',
children: [
{
id: '0-7-0',
title: '0-7-0',
},
{
id: '0-7-1',
title: '0-7-1',
},
],
},
{
id: '0-8',
title: '0-8',
children: [
{
id: '0-8-0',
title: '0-8-0',
},
{
id: '0-8-1',
title: '0-8-1',
},
],
},
],
},
{
id: '1',
title: '1',
children: [
{
id: '1-0',
title: '1-0',
},
{
id: '1-1',
title: '1-1',
},
],
},
{
id: '2',
title: '2',
children: [
{
id: '2-0',
title: '2-0',
},
{
id: '2-1',
title: '2-1',
},
],
},
])
return (
<>
展示搜索结果:拍平模式(默认)
展示搜索结果:级联模式
>
)
}
```
### 自定义搜索筛选规则
通过 filterOption 可自定义搜索条件的算法
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
import { match } from 'pinyin-pro'
export const FilterOptions = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
// 注意 filterOption 是影响搜索渲染的,是完全受控的,useCallback 包裹可以减少无效的重渲染,提升性能
const filterOptionMemo = React.useCallback((keyword: string, item: any) => {
if (item.children) return false
const _match = (node: any) =>
typeof node.title === 'string' && !!match(node.title as string, keyword)
const matchUp = (node: any) => {
let found = _match(node)
let { parent } = node
if (parent && !found) {
const ancestors = [] as any[]
while (parent) {
ancestors.push(parent)
parent = parent.parent
}
found = ancestors.some((item: any) => _match(item))
console.log(ancestors, found)
}
return found
}
const matchDown = (node: any) => {
let found = _match(node)
const { children } = node
if (children && !found) {
found = children.some((item: any) => matchDown(item))
}
return found
}
const result = matchUp(item) || matchDown(item)
return result
}, [])
return (
<>
>
)
}
```
### 选中任意层级
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const SelectChange = () => {
const [data] = React.useState([
{
id: '0',
title: '0',
children: [
{
id: '0-0',
title: '0-0',
children: [
{
id: '0-0-0',
title: '0-0-0',
},
{
id: '0-0-1',
title: '0-0-1',
},
{
id: '0-0-2',
title: '0-0-2',
},
],
},
{
id: '0-1',
title: '0-1',
children: [
{
id: '0-1-0',
title: '0-1-0',
},
{
id: '0-1-1',
title: '0-1-1',
},
],
},
{
id: '0-2',
title: '0-2',
disabled: false,
children: [
{
id: '0-2-0',
title: '0-2-0',
},
{
id: '0-2-1',
title: '0-2-1',
},
],
},
{
id: '0-3',
title: '0-3',
children: [
{
id: '0-3-0',
title: '0-3-0',
},
{
id: '0-3-1',
title: '0-3-1',
},
{
id: '0-3-2',
title: '0-3-2',
},
],
},
{
id: '0-4',
title: '0-4',
children: [
{
id: '0-4-0',
title: '0-4-0',
},
{
id: '0-4-1',
title: '0-4-1',
},
],
},
{
id: '0-5',
title: '0-5',
children: [
{
id: '0-5-0',
title: '0-5-0',
},
{
id: '0-5-1',
title: '0-5-1',
},
],
},
],
},
{
id: '1',
title: '1',
children: [
{
id: '1-0',
title: '1-0',
disabledCheckbox: true,
},
{
id: '1-1',
title: '1-1',
},
],
},
])
return (
<>
>
)
}
```
### 选择后是否关闭弹窗
用于 changeOnSelect 模式下控制点击父节点时是否关闭弹窗
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const SelectClose = () => {
const [data] = React.useState([
{
id: '0',
title: '0',
children: [
{
id: '0-0',
title: '0-0',
children: [
{
id: '0-0-0',
title: '0-0-0',
},
{
id: '0-0-1',
title: '0-0-1',
},
{
id: '0-0-2',
title: '0-0-2',
},
],
},
{
id: '0-1',
title: '0-1',
children: [
{
id: '0-1-0',
title: '0-1-0',
},
{
id: '0-1-1',
title: '0-1-1',
},
],
},
{
id: '0-2',
title: '0-2',
disabled: false,
children: [
{
id: '0-2-0',
title: '0-2-0',
},
{
id: '0-2-1',
title: '0-2-1',
},
],
},
{
id: '0-3',
title: '0-3',
children: [
{
id: '0-3-0',
title: '0-3-0',
},
{
id: '0-3-1',
title: '0-3-1',
},
{
id: '0-3-2',
title: '0-3-2',
},
],
},
{
id: '0-4',
title: '0-4',
children: [
{
id: '0-4-0',
title: '0-4-0',
},
{
id: '0-4-1',
title: '0-4-1',
},
],
},
{
id: '0-5',
title: '0-5',
children: [
{
id: '0-5-0',
title: '0-5-0',
},
{
id: '0-5-1',
title: '0-5-1',
},
],
},
],
},
{
id: '1',
title: '1',
children: [
{
id: '1-0',
title: '1-0',
disabledCheckbox: true,
},
{
id: '1-1',
title: '1-1',
},
],
},
])
return (
<>
>
)
}
```
### hover 展开次级菜单
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const HoverExpand = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机',
children: [
{
id: '小米',
title: '小米',
children: [
{
id: '小米3',
title: '小米3',
},
{
id: '小米4',
title: '小米4',
},
],
},
{
id: '红米',
title: '红米',
children: [
{
id: '红米3',
title: '红米3',
},
{
id: '红米4',
title: '红米4',
},
],
},
],
},
{
id: '电视',
title: '电视',
children: [
{
id: '小米电视4A',
title: '小米电视4A',
},
{
id: '小米电视4C',
title: '小米电视4C',
},
],
},
])
return (
<>
>
)
}
```
### 异步加载数据
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
import Alert from '@hi-ui/alert'
export const Dynamic = () => {
const [treeData] = React.useState([
{
id: 1,
title: '小米',
children: [
{
id: 2,
title: '技术',
children: [
{ id: 3, title: '后端' },
{ id: 4, title: '运维' },
{ id: 5, title: '前端' },
],
},
{ id: 6, title: '产品' },
],
},
{
id: 11,
title: '小米',
children: [
{ id: 22, title: '技术' },
{ id: 66, title: '产品' },
],
},
])
// 加载节点
const loadChildren = async (node) => {
return fetch(`https://my-json-server.typicode.com/hiui-group/db/conditiondata?id=${node.id}`)
.then((res) => res.json())
.then((data) => {
if (data[0]) {
data[0].id = Math.random()
}
// setTreeData((prev) => {
// const nextData = cloneTree(prev)
// const loadNode = findNode(node.id, nextData)
// loadNode.children = data
// console.log(loadNode, nextData)
// return nextData
// })
return data
})
}
return (
<>
>
)
}
```
### 自定义回显展示
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const DisplayRender = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
return (
<>
{
const titleArr = []
while (option.parent) {
titleArr.push(option.title)
option = option.parent as any
}
return titleArr.reverse().join(' | ')
}}
>
>
)
}
```
### 自定义选项展示
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const TitleRender = () => {
const [data] = React.useState([
{
id: '1',
title: '手机t',
children: [
{
id: '1-1',
title: '小米t',
children: [
{
id: '1-1-1',
title: '小米3t',
},
{
id: '1-1-2',
title: '小米4t',
},
],
},
{
id: '1-2',
title: '红米t',
children: [
{
id: '1-2-1',
title: '红米3t',
},
{
id: '1-2-2',
title: '红米4t',
},
],
},
],
},
{
id: '2',
title: '电视t',
children: [
{
id: '2-1',
title: '小米电视4At',
},
{
id: '2-2',
title: '小米电视4Ct',
},
],
},
])
return (
<>
{
console.log(item, keyword)
if (keyword) {
// 自定义搜索结果展示:可以自定义控制关键词高亮,夹带 icon 等场景
return {`${keyword}: ${item.title}`}
}
return {`${item.title}(${item.id})`}
}}
onChange={(...args) => {
console.log('onChange', ...args)
}}
>
>
)
}
```
### 吸底内容条
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const Footer = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
return (
<>
{
console.log('onChange', ...args)
}}
renderExtraFooter={() => custom footer
}
>
>
)
}
```
### 自定义下拉菜单内容
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const DropdownColumnRender = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
{
id: '1',
title: '小米1',
},
{
id: '2',
title: '小米2',
},
{
id: '3',
title: '小米3',
},
{
id: '4',
title: '小米4',
},
{
id: '5',
title: '小米5',
},
{
id: '6',
title: '小米6',
},
{
id: '7',
title: '小米7',
},
])
return (
<>
{
console.log('onChange', ...args)
}}
// 如果有样式不满足需求,可以给弹出层设置独有的 className 来进行样式覆写
overlay={{ className: 'my-overlay' }}
dropdownColumnRender={(menu, level) => {
return level < 5 ? (
{React.cloneElement(menu, { style: { height: 180 } })}
) : (
menu
)
}}
>
>
)
}
```
### 字段别名
数据中的字段名非title,id或disabled时使用
```tsx
import React from 'react'
import { Cascader } from '@hi-ui/cascader'
export const FieldNames = () => {
const [data] = React.useState([
{
value: '0',
label: '0',
kids: [
{
value: '0-0',
label: '0-0',
kids: [
{
value: '0-0-0',
label: '0-0-0',
},
{
value: '0-0-1',
label: '0-0-1',
},
{
value: '0-0-2',
label: '0-0-2',
},
],
},
{
value: '0-1',
label: '0-1',
kids: [
{
value: '0-1-0',
label: '0-1-0',
},
{
value: '0-1-1',
label: '0-1-1',
},
],
},
{
value: '0-2',
label: '0-2',
kids: [
{
value: '0-2-0',
label: '0-2-0',
},
{
value: '0-2-1',
label: '0-2-1',
},
],
},
],
},
{
value: '1',
label: '1',
kids: [
{
value: '1-0',
label: '1-0',
},
{
value: '1-1',
label: '1-1',
},
],
},
{
value: '2',
label: '2',
kids: [
{
value: '2-0',
label: '2-0',
},
{
value: '2-1',
label: '2-1',
},
],
},
])
return (
<>
>
)
}
```
### 受控显隐
自定义控制下拉选项菜单显隐
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const Visible = () => {
const [visible, setVisible] = React.useState(true)
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
return (
<>
setVisible(true)}
overlay={{ onOutsideClick: () => setVisible(false) }}
clearable
placeholder="请选择品类"
defaultValue={['手机', '红米', '红米4']}
data={data}
onChange={(...args) => {
console.log('onChange', ...args)
}}
/>
>
)
}
```
### 自定义触发器
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
import Input from '@hi-ui/input'
export const CustomRender = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
return (
<>
{
return
}}
>
>
)
}
```
### 大数据
支持大数据下的虚拟滚动
```tsx
import React from 'react'
import Cascader from '@hi-ui/cascader'
export const Virtual = () => {
const [data] = React.useState([
// 随机生成 10 * 10 * 1000 条的级联数据
...Array.from({ length: 10 }, (_, index) => ({
id: `item-${index}`,
title: `item-${index}`,
children: Array.from({ length: 10 }, (_, index2) => ({
id: `item-${index}-${index2}`,
title: `item-${index}-${index2}`,
children: Array.from({ length: 1000 }, (_, index3) => ({
id: `item-${index}-${index2}-${index3}`,
title: `item-${index}-${index2}-${index3}`,
})),
})),
})),
])
return (
<>
{
console.log('onChange', ...args)
}}
virtual
>
>
)
}
```
### 自定义头尾
```tsx
import React, { useState } from 'react'
import Cascader from '@hi-ui/cascader'
export const ExtraRender = () => {
const [data] = useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
return (
<>
custom header
}
renderExtraFooter={() => 'custom footer'}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对 Cascader 各元素进行细粒度的样式控制(含 Picker 的 root/container/panel 等及 menuList/menu/option)
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Cascader, { CascaderSemanticName } from '@hi-ui/cascader'
export const Semantic = () => {
const [data] = React.useState([
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
])
const [selected, setSelected] = useState()
return (
<>
custom header
}
renderExtraFooter={() => 'custom footer'}
// @ts-ignore
overlay={{ flip: false }}
/>
(
setSelected(dataItem.title as CascaderSemanticName)}
onMouseLeave={() => setSelected(undefined)}
>
)}
/>
>
)
}
```
## Props
### Cascader Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| expandTrigger | 次级菜单的展开方式 | CascaderExpandTriggerEnum | "click" \| "hover" | - |
| searchable | 是否可搜索(仅在 title 为字符串时支持) | boolean | true \| false | - |
| clearable | 是否可清空 | boolean | true \| false | - |
| emptyContent | 设置选项为空时展示的内容 | ReactNode | - | - |
| render | 自定义渲染节点的 title 内容 | ((item: CascaderItemEventData, keyword?: string) => ReactNode) \| undefined | (item: CascaderItemEventData, keyword?: string \| undefined) => ReactNode | - |
| displayRender | 自定义选择后触发器所展示的内容,只在 title 为字符串时有效 | ((checkedOption: CascaderItemEventData, checkedOptionPaths: CascaderItemEventData\[]) => ReactNode) | - | - |
| placeholder | 触发器输入框占位符 | string | - | - |
| searchPlaceholder | 搜索输入框占位符 | string | - | - |
| filterOption | 自定义搜索过滤器,仅在 searchable 为 true 时有效
第一个参数为输入的关键字,
第二个为数据项,返回值为 true 时将出现在结果项 | ((keyword: string, item: CascaderItemEventData) => boolean) | - | - |
| overlay | 自定义控制 popper 行为 | PopperOverlayProps | - | - |
| appearance | 设置展现形式 | CascaderAppearanceEnum | "line" \| "filled" \| "unset" \| "borderless" \| "contained" | - |
| label | 设置输入框 label 内容,仅在 appearance 为 contained 时生效 | ReactNode | - | - |
| flattedSearchResult | 搜索结果拍平展示 | boolean | true \| false | - |
| renderExtraFooter | 自定义下拉菜单底部渲染 | (() => ReactNode) | - | - |
| renderExtraHeader | 自定义下拉菜单顶部渲染 | (() => ReactNode) | - | - |
| dropdownColumnRender | 自定义下拉菜单每列渲染 | ((menu: ReactElement\>, level: number) => ReactNode) | (menu: ReactElement\>, level: number) => ReactNode | - |
| size | 设置尺寸 | HiBaseSizeEnum | "xs" \| "sm" \| "md" \| "lg" | - |
| prefix | 选择框前置内容 | ReactNode | - | - |
| suffix | 选择框后置内容 | ReactNode | - | - |
| customRender | 自定义触发器 | ReactNode \| ((selectedItem: CascaderItemEventData \| null, value?: ReactText\[]) => ReactNode) | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| (selectedItem: CascaderItemEventData \| null, value?: ReactText\[] \| undefined) => ReactNode | - |
| onClear | 点击关闭按钮时触发 | (() => void) | - | - |
| virtual | 是否开启虚拟滚动 | boolean | true \| false | - |
| onItemClick | 点击选项时触发 | ((event: MouseEvent\, eventOption: CascaderItemEventData) => void) | - | - |
| showIndicator | 是否展示箭头 | boolean | true \| false | - |
| loading | 是否在加载中 | boolean | true \| false | - |
| disabled | 是否禁用 | boolean | true \| false | - |
| loadingContent | 加载中时的提示 | ReactNode | - | - |
| showEmpty | 展示未搜索结果 | boolean | true \| false | - |
| optionWidth | 自定义下拉选项宽度 | Width\ | string \| number \| string & {} | - |
| overlayClassName | 下拉根元素的类名称 | string | - | - |
| keyword | 搜索关键字,searchable 为 true 时有效 | string | - | - |
| creatableInSearch | 在搜索状态下是否可创建选项 | boolean | true \| false | - |
| creatableInSearchVisible | 是否显示「创建选项」入口。为 false 时不显示。
不传(undefined)时保持兼容:只要有搜索词即显示创建入口。
Select/CheckSelect 会传入此 prop,实现「仅当无结果或关键字与结果无全匹配时显示」。 | boolean | true \| false | - |
| createTitle | 创建选项时展示的标题 | string | - | - |
| onCreate | 创建选项时触发回调 | ((keyword: string) => void) | - | - |
| onSearch | 搜索时触发回调 | ((keyword: string) => void) | - | - |
| clearSearchOnClosed | 是否在关闭时清除搜索 | boolean | true \| false | - |
| closeOnEsc | 开启 Esc 快捷键关闭 | boolean | true \| false | - |
| visible | 控制气泡卡片的显示和隐藏(受控) | boolean | true \| false | - |
| onOpen | 下拉菜单打开时回调 | (() => void) | - | - |
| onClose | 下拉菜单关闭时回调 | (() => void) | - | - |
| onOverlayScroll | 下拉列表滚动时的回调 | (() => void) | - | - |
| gutterGap | 气泡卡片与触发器的间距 | number | - | - |
| innerRef | 提供辅助方法的内部引用 | Ref\ | - | - |
| invalid | 开启表单控件组件输入无效态 | boolean | true \| false | - |
| fieldNames | 设置 data 中 id, title, disabled, children 对应的 key | Record\ | - | - |
| data | 设置选择项数据源 | CascaderDataItem\[] | - | - |
| value | 设置当前选中值 | ReactText\[] | - | - |
| defaultValue | 设置当前选中值默认值 | ReactText\[] | - | - |
| onChange | 选中值改变时的回调 | ((value: ReactText\[], targetOption?: CascaderItemEventData, optionPaths?: FlattedCascaderDataItem\[] \| undefined) => void) \| undefined | (value: ReactText\[], targetOption?: CascaderItemEventData \| undefined, optionPaths?: FlattedCascaderDataItem\[] \| undefined) => void | - |
| changeOnSelect | 是否启用选择即改变功能 | boolean | true \| false | - |
| closeOnSelect | 是否启用选择即关闭(用于 changeOnSelect 模式下控制父节点点击交互) | boolean | true \| false | "true" |
| onLoadChildren | 异步请求更新数据 | ((item: CascaderItemEventData, idPaths: ReactText\[]) => void \| Promise\) | (item: CascaderItemEventData, idPaths: ReactText\[]) => void \| Promise\ | - |
| classNames | | CascaderSemanticClassNames | - | - |
| styles | | CascaderSemanticStyles | - | - |
## Type
### CascaderDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | --------------------------------------------------------------------- | ------------------ | ------------- | ------ |
| id | 选择项值,唯一 id | ReactText | - | - |
| title | 选项标题 | ReactNode | - | - |
| children | 下一级选项列表 | CascaderDataItem[] | - | - |
| disabled | 是否禁用该节点(将禁用级联点击,展开,如果开启 checkbox,也将被禁用) | boolean | true \| false | false |
| isLeaf | 是否为叶子节点,当 children 为空数组也表示为叶子结点 | boolean | true \| false | - |
### CascaderItemEventData
> 继承自 CascaderDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ------------------------------ | ----------------------- | ------ | ------ |
| children | 下一级选项列表 | CascaderItemEventData[] | - | - |
| raw | 关联用户传入的原始数据对象 | CascaderDataItem | - | - |
| depth | 该节点的层级,从 0(顶层)开始 | number | - | - |
| parent | 该节点的父节点 | CascaderItemEventData | - | - |
### PopperOverlayProps
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | ---------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| className | 弹层类名 | string | - | - |
| matchWidth | 自动计算匹配吸附元素的宽度与其一致 | boolean | true \| false | false |
| placement | 相对吸附元素的位置 | PopperPlacementEnum | "top" \| "bottom" \| "right" \| "left" \| "top-start" \| "top-end" \| "bottom-start" \| "bottom-end" \| "right-start" \| "right-end" \| "left-start" \| "left-end" \| "auto" \| "auto-start" \| "auto-end" | "bottom-start" |
| container | 指定 portal 的容器 | HTMLElement | - | - |
| disabledPortal | 禁用 portal | boolean | true \| false | false |
| arrow | 是否展示箭头 | boolean | true \| false | false |
# CheckCascader 多项级联选择器
通过采用多级分类的方式将选项进行分隔,便于用户完成多项选择,在不同类型之间切换。
## 使用示例
### 基础用法
展示从多个收起的备选项中选出的多个选项
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const Basic = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
>
)
}
```
### 展现形式
设置展现形式
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const Appearance = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
Filled
Line
Unset
Borderless
Contained
>
)
}
```
### 展示全部已选项
设置后,选中内容超出宽度时会换行展示
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const TagInputWrap = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const Size = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
xs
sm
md
lg
>
)
}
```
### 回显模式
不同模式下,选中项的内容不一样,默认是 `ALL` 模式,无论父子节点,选中后就会展示。
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const CheckedMode = () => {
const [data] = React.useState([
{
id: 1,
title: '小米',
children: [
{
id: 2,
title: '技术',
children: [
{ id: 3, title: '后端' },
{ id: 4, title: '运维' },
{ id: 5, title: '前端' },
],
},
{ id: 6, title: '产品' },
],
},
{
id: 11,
title: '小米',
children: [
{ id: 22, title: '技术' },
{ id: 66, title: '产品' },
],
},
])
return (
<>
ALL(默认)
PARENT
CHILD
SEPARATE
>
)
}
```
### 禁用状态
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const Disabled = () => {
const [data] = React.useState(() => {
const data = [
{
id: '0',
title: '0',
children: [
{
id: '0-0',
title: '0-0',
children: [
{
id: '0-0-0',
title: '0-0-0',
},
{
id: '0-0-1',
title: '0-0-1',
},
{
id: '0-0-2',
title: '0-0-2',
},
],
},
{
id: '0-1',
title: '0-1',
checkable: true,
children: [
{
id: '0-1-0',
title: '0-1-0',
},
{
id: '0-1-1',
title: '0-1-1',
},
],
},
{
id: '0-2',
title: '0-2',
checkable: true,
disabled: true,
children: [
{
id: '0-2-0',
title: '0-2-0',
},
{
id: '0-2-1',
title: '0-2-1',
},
],
},
{
id: '0-3',
title: '0-3',
children: [
{
id: '0-3-0',
title: '0-3-0',
},
{
id: '0-3-1',
title: '0-3-1',
},
{
id: '0-3-2',
title: '0-3-2',
},
],
},
{
id: '0-4',
title: '0-4',
checkable: true,
disabledCheckbox: true,
children: [
{
id: '0-4-0',
title: '0-4-0',
},
{
id: '0-4-1',
title: '0-4-1',
},
],
},
{
id: '0-5',
title: '0-5',
checkable: true,
children: [
{
id: '0-5-0',
title: '0-5-0',
},
{
id: '0-5-1',
title: '0-5-1',
},
],
},
],
},
{
id: '1',
title: '1',
children: [
{
id: '1-0',
title: '1-0',
disabledCheckbox: true,
children: [
{
id: '1-0-0',
title: '1-0-0',
checkable: false,
},
{
id: '1-0-1',
title: '1-0-1',
children: [
{
id: '1-0-1-0',
title: '1-0-1-0',
},
{
id: '1-0-1-1',
title: '1-0-1-1',
},
],
},
{
id: '1-0-2',
title: '1-0-2',
},
],
},
{
id: '1-1',
title: '1-1',
checkable: false,
},
{
id: '1-2',
title: '1-2',
},
{
id: '1-3',
title: '1-3',
},
],
},
]
return data
})
return (
<>
整体禁用
禁用某个选项
>
)
}
```
### 禁用 checkbox 级联
禁用后只能用于展示勾选状态,无法进行操作
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const DisabledCheckboxCascaded = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
disabledCheckboxCascaded: true,
children: [
{
id: '小米电视4A',
title: '小米电视4At',
disabled: true,
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = true
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
>
)
}
```
### 带搜索
选项数量较大,不熟悉数据的结构关系情况下,用搜索关键词的方式快速定位
```tsx
import React from 'react'
import CheckCascader, { CheckCascaderDataItem } from '@hi-ui/check-cascader'
export const Search = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: 'up-1',
title: 'up',
children: [
{
id: 'up-1-0',
title: '小米',
children: [
{
id: 'up-1-0-0',
title: 'leaf',
},
],
},
{
id: 'up-1-1',
title: '1-1',
},
],
},
{
id: '0',
title: '0',
children: [
{
id: '0-0',
title: '0-0',
children: [
{
id: '0-0-0',
title: '0-0-0',
},
{
id: '0-0-1',
title: '0-0-1',
},
{
id: '0-0-2',
title: '0-0-2',
},
],
},
{
id: '0-1',
title: '0-1',
checkable: true,
children: [
{
id: '0-1-0',
title: '0-1-0',
},
{
id: '0-1-1',
title: '0-1-1',
},
],
},
{
id: '0-2',
title: '0-2',
checkable: true,
children: [
{
id: '0-2-0',
title: '0-2-0',
},
{
id: '0-2-1',
title: '0-2-1',
},
],
},
{
id: '0-3',
title: '0-3',
children: [
{
id: '0-3-0',
title: '0-3-0',
},
{
id: '0-3-1',
title: '0-3-1',
},
{
id: '0-3-2',
title: '0-3-2',
},
],
},
{
id: '0-4',
title: '0-4',
checkable: true,
children: [
{
id: '0-4-0',
title: '0-4-0',
},
{
id: '0-4-1',
title: '0-4-1',
},
],
},
{
id: '0-5',
title: '0-5',
checkable: true,
children: [
{
id: '0-5-0',
title: '0-5-0',
},
{
id: '0-5-1',
title: '0-5-1',
},
],
},
{
id: '0-6',
title: '0-6',
children: [
{
id: '0-6-0',
title: '0-6-0',
},
{
id: '0-6-1',
title: '0-6-1',
},
{
id: '0-6-2',
title: '0-6-2',
},
],
},
{
id: '0-7',
title: '0-7',
checkable: true,
children: [
{
id: '0-7-0',
title: '0-7-0',
},
{
id: '0-7-1',
title: '0-7-1',
},
],
},
{
id: '0-8',
title: '0-8',
checkable: true,
children: [
{
id: '0-8-0',
title: '0-8-0',
},
{
id: '0-8-1',
title: '0-8-1',
},
],
},
],
},
{
id: '1',
title: '1',
children: [
{
id: '1-0',
title: '1-0',
},
{
id: '1-1',
title: '1-1',
},
],
},
{
id: '2',
title: '2',
children: [
{
id: '2-0',
title: '2-0',
},
{
id: '2-1',
title: '2-1',
},
],
},
]
const getDataOnlyLeafCheckable = (data: CheckCascaderDataItem[]) => {
return data.map((item: CheckCascaderDataItem) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
} else {
item.checkable = true
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
console.log(dataOnlyLeafCheckable)
return (
<>
展示搜索结果:拍平模式(默认)
展示搜索结果:级联模式
>
)
}
```
### 查看已选
只展示选中的选项
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const OnlyChecked = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
>
)
}
```
### 选择即改变
选中选项即可完成勾选,配合 hover 展开使用
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const SelectChange = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '0',
title: '0',
children: [
{
id: '0-0',
title: '0-0',
children: [
{
id: '0-0-0',
title: '0-0-0',
},
{
id: '0-0-1',
title: '0-0-1',
},
{
id: '0-0-2',
title: '0-0-2',
},
],
},
{
id: '0-1',
title: '0-1',
checkable: true,
children: [
{
id: '0-1-0',
title: '0-1-0',
},
{
id: '0-1-1',
title: '0-1-1',
},
],
},
{
id: '0-2',
title: '0-2',
checkable: true,
disabled: false,
children: [
{
id: '0-2-0',
title: '0-2-0',
},
{
id: '0-2-1',
title: '0-2-1',
},
],
},
{
id: '0-3',
title: '0-3',
children: [
{
id: '0-3-0',
title: '0-3-0',
},
{
id: '0-3-1',
title: '0-3-1',
},
{
id: '0-3-2',
title: '0-3-2',
},
],
},
{
id: '0-4',
title: '0-4',
checkable: true,
disabledCheckbox: true,
children: [
{
id: '0-4-0',
title: '0-4-0',
},
{
id: '0-4-1',
title: '0-4-1',
},
],
},
{
id: '0-5',
title: '0-5',
checkable: true,
children: [
{
id: '0-5-0',
title: '0-5-0',
},
{
id: '0-5-1',
title: '0-5-1',
},
],
},
],
},
{
id: '1',
title: '1',
children: [
{
id: '1-0',
title: '1-0',
disabledCheckbox: true,
},
{
id: '1-1',
title: '1-1',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
} else {
item.checkable = true
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
>
)
}
```
### 异步加载数据
```tsx
import Alert from '@hi-ui/alert'
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const Dynamic = () => {
const [treeData] = React.useState([
{
id: 1,
title: '小米',
children: [
{
id: 2,
title: '技术',
children: [
{ id: 3, title: '后端' },
{ id: 4, title: '运维' },
{ id: 5, title: '前端' },
],
},
{ id: 6, title: '产品' },
],
},
{
id: 11,
title: '小米',
children: [
{ id: 22, title: '技术' },
{ id: 66, title: '产品' },
],
},
])
// 加载节点
const loadChildren = async (node) => {
return fetch(`https://my-json-server.typicode.com/hiui-group/db/conditiondata?id=${node.id}`)
.then((res) => res.json())
.then((data) => {
if (data[0]) {
data[0].id = Math.random()
}
// setTreeData((prev) => {
// const nextData = cloneTree(prev)
// const loadNode = findNode(node.id, nextData)
// loadNode.children = data
// console.log(loadNode, nextData)
// return nextData
// })
return data
})
}
return (
<>
>
)
}
```
### 自定义回显展示
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const DisplayRender = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
console.log(dataOnlyLeafCheckable)
return (
<>
{
const titleArr = []
while (option.parent) {
titleArr.push(option.title)
option = option.parent
}
return titleArr.reverse().join(' | ')
}}
>
>
)
}
```
### 吸底内容条
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const Footer = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
>
)
}
```
### 自定义下拉菜单内容
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const DropdownColumnRender = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
{
id: '1',
title: '小米1',
},
{
id: '2',
title: '小米2',
},
{
id: '3',
title: '小米3',
},
{
id: '4',
title: '小米4',
},
{
id: '5',
title: '小米5',
},
{
id: '6',
title: '小米6',
},
{
id: '7',
title: '小米7',
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
{
return level < 5 ? (
{React.cloneElement(menu, { style: { height: 180 } })}
) : (
menu
)
}}
>
>
)
}
```
### 前后内置元素
将选择框与内置的其他元素组合使用
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
import { AppStoreOutlined, InfoCircleOutlined } from '@hi-ui/icons'
export const Addon = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
}
suffix={}
changeOnSelect
data={dataOnlyLeafCheckable}
onChange={console.log}
>
>
)
}
```
### 自定义触发器
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
import Input from '@hi-ui/input'
export const CusotmRender = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
{
let value = ''
if (data) {
value = data?.map((item) => item?.title).join(',')
}
return
}}
>
>
)
}
```
### 大数据
支持大数据下的虚拟滚动
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const Virtual = () => {
const [dataOnlyLeafCheckable] = React.useState(() => {
const data = [
// 随机生成 10 * 10 * 1000 条的级联数据
...Array.from({ length: 100 }, (_, index) => ({
id: `item-${index}`,
title: `item-${index}`,
children: Array.from({ length: 10 }, (_, index2) => ({
id: `item-${index}-${index2}`,
title: `item-${index}-${index2}`,
children: Array.from({ length: 1000 }, (_, index3) => ({
id: `item-${index}-${index2}-${index3}`,
title: `item-${index}-${index2}-${index3}`,
})),
})),
})),
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
>
)
}
```
### 全选
```tsx
import React from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const CheckAll = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
>
)
}
```
### 自定义头尾
```tsx
import React, { useState } from 'react'
import CheckCascader from '@hi-ui/check-cascader'
export const ExtraRender = () => {
const [dataOnlyLeafCheckable] = useState(() => {
const data = [
{
id: '手机',
title: '手机t',
children: [
{
id: '小米',
title: '小米t',
children: [
{
id: '小米3',
title: '小米3t',
},
{
id: '小米4',
title: '小米4t',
},
],
},
{
id: '红米',
title: '红米t',
children: [
{
id: '红米3',
title: '红米3t',
},
{
id: '红米4',
title: '红米4t',
},
],
},
],
},
{
id: '电视',
title: '电视t',
children: [
{
id: '小米电视4A',
title: '小米电视4At',
},
{
id: '小米电视4C',
title: '小米电视4Ct',
},
],
},
]
const getDataOnlyLeafCheckable = (data: any) => {
return data.map((item: any) => {
if (item.children) {
item.checkable = item.checkable ?? false
item.children = getDataOnlyLeafCheckable(item.children)
}
return item
})
}
const dataOnlyLeafCheckable = getDataOnlyLeafCheckable(data)
return dataOnlyLeafCheckable
})
return (
<>
custom header
}
renderExtraFooter={() => 'custom footer'}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对 CheckCascader 各元素进行细粒度的样式控制(含 Picker 的 root/container/panel 等及 menuList/menu/option)
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import CheckCascader, { CheckCascaderSemanticName } from '@hi-ui/check-cascader'
export const Semantic = () => {
const [data] = React.useState(() => [
{
id: '手机',
title: '手机',
children: [
{
id: '小米',
title: '小米',
children: [
{ id: '小米3', title: '小米3' },
{ id: '小米4', title: '小米4' },
],
},
{
id: '红米',
title: '红米',
children: [
{ id: '红米3', title: '红米3' },
{ id: '红米4', title: '红米4' },
],
},
],
},
{
id: '电视',
title: '电视',
children: [
{ id: '小米电视4A', title: '小米电视4A' },
{ id: '小米电视4C', title: '小米电视4C' },
],
},
])
const [selected, setSelected] = useState()
return (
<>
custom header
}
renderExtraFooter={() => 'custom footer'}
// @ts-ignore
overlay={{ flip: false }}
/>
(
setSelected(dataItem.title as CheckCascaderSemanticName)}
onMouseLeave={() => setSelected(undefined)}
>
)}
/>
>
)
}
```
## Props
### CheckCascader Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| data | 设置选择项数据源 | CheckCascaderDataItem\[] | - | \[] |
| fieldNames | 设置 data 中字段对应的 key | HiBaseFieldNames | - | - |
| value | 设置当前多选值 | ReactText\[]\[] | - | - |
| defaultValue | 设置当前多选值默认值 | ReactText\[]\[] | - | \[] |
| onChange | 多选值改变时的回调 | ((values: ReactText\[]\[], targetOption?: CheckCascaderItemEventData, optionPaths?: FlattedCheckCascaderDataItem\[] \| undefined) => void) \| undefined | (values: ReactText\[]\[], targetOption?: CheckCascaderItemEventData \| undefined, optionPaths?: FlattedCheckCascaderDataItem\[] \| undefined) => void | - |
| expandTrigger | 次级菜单的展开方式 | CheckCascaderExpandTriggerEnum | "click" \| "hover" | - |
| searchable | 是否可搜索(仅在 title 为字符串时支持) | boolean | true \| false | - |
| clearable | 是否可清空 | boolean | true \| false | - |
| onClear | 点击关闭按钮时触发 | (() => void) | - | - |
| disabled | 是否禁止使用 | boolean | true \| false | false |
| emptyContent | 设置选项为空时展示的内容 | ReactNode | - | - |
| changeOnSelect | 是否启用选择即改变功能 | boolean | true \| false | - |
| render | 自定义渲染节点的 title 内容 | ((item: CheckCascaderItemEventData) => ReactNode) | - | - |
| displayRender | 自定义选择后触发器所展示的内容 | ((checkedOption: FlattedCheckCascaderDataItem) => ReactNode) | - | - |
| checkCascaded | 支持 checkbox 级联(正反选)功能 | boolean | true \| false | - |
| flattedSearchResult | 搜索结果拍平展示 | boolean | true \| false | true |
| placeholder | 触发器输入框占位符 | string | - | - |
| searchPlaceholder | 搜索输入框占位符 | string | - | - |
| onLoadChildren | 异步请求更新数据 | ((item: CheckCascaderItemEventData, idPaths: ReactText\[]) => void \| Promise\) | (item: CheckCascaderItemEventData, idPaths: ReactText\[]) => void \| Promise\ | - |
| appearance | 设置展现形式 | CheckCascaderAppearanceEnum | "line" \| "filled" \| "unset" \| "borderless" \| "contained" | - |
| label | 设置输入框 label 内容,仅在 appearance 为 contained 时生效 | ReactNode | - | - |
| filterOption | 自定义搜索过滤器,仅在 searchable 为 true 时有效
第一个参数为输入的关键字,
第二个为数据项,返回值为 true 时将出现在结果项 | ((keyword: string, item: any) => boolean) | - | - |
| checkedMode | 多选数据交互时回填、回显模式
PARENT: 当所有子节点被选中时将只保留父节点
ALL: 所有被选中节点,不区分父子节点(不支持异步数据加载勾选checkbox)
CHILD: 仅显示子节点(不支持异步数据加载勾选checkbox)
SEPARATE:父子完全独立受控 | "PARENT" \| "CHILD" \| "ALL" \| "SEPARATE" | "PARENT" \| "CHILD" \| "ALL" \| "SEPARATE" | - |
| tagInputProps | TagInput 参数设置 | TagInputMockProps | - | - |
| size | 设置尺寸 | HiBaseSizeEnum | "xs" \| "sm" \| "md" \| "lg" | - |
| prefix | 选择框前置内容 | ReactNode | - | - |
| suffix | 选择框后置内容 | ReactNode | - | - |
| renderExtraFooter | 自定义下拉菜单底部渲染 | (() => ReactNode) | - | - |
| renderExtraHeader | 自定义下拉菜单顶部渲染 | (() => ReactNode) | - | - |
| dropdownColumnRender | 自定义下拉菜单每列渲染 | ((menu: ReactElement\>, level: number) => ReactNode) | (menu: ReactElement\>, level: number) => ReactNode | - |
| customRender | 自定义触发器 | ReactNode \| ((selectItems: (FlattedCheckCascaderDataItem)\[], value?: ReactText\[] \| undefined) => ReactNode) | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| (selectItems: (FlattedCheckCascaderDataItem \| undefined)\[], value?: ReactText\[] \| undefined) => ReactNode | - |
| showOnlyShowChecked | 是否只展示选中的选项 | boolean | true \| false | - |
| virtual | 是否开启虚拟滚动 | boolean | true \| false | - |
| showCheckAll | 是否开启全选功能 | boolean | true \| false | - |
| showIndicator | 是否展示箭头 | boolean | true \| false | true |
| loading | 是否在加载中 | boolean | true \| false | - |
| loadingContent | 加载中时的提示 | ReactNode | - | - |
| showEmpty | 展示未搜索结果 | boolean | true \| false | - |
| optionWidth | 自定义下拉选项宽度 | Width\ | string \| number \| string & {} | - |
| overlayClassName | 下拉根元素的类名称 | string | - | - |
| keyword | 搜索关键字,searchable 为 true 时有效 | string | - | - |
| creatableInSearch | 在搜索状态下是否可创建选项 | boolean | true \| false | - |
| creatableInSearchVisible | 是否显示「创建选项」入口。为 false 时不显示。
不传(undefined)时保持兼容:只要有搜索词即显示创建入口。
Select/CheckSelect 会传入此 prop,实现「仅当无结果或关键字与结果无全匹配时显示」。 | boolean | true \| false | - |
| createTitle | 创建选项时展示的标题 | string | - | - |
| onCreate | 创建选项时触发回调 | ((keyword: string) => void) | - | - |
| onSearch | 搜索时触发回调 | ((keyword: string) => void) | - | - |
| clearSearchOnClosed | 是否在关闭时清除搜索 | boolean | true \| false | - |
| overlay | 自定义控制 popper 行为 | PopperOverlayProps | - | - |
| closeOnEsc | 开启 Esc 快捷键关闭 | boolean | true \| false | - |
| visible | 控制气泡卡片的显示和隐藏(受控) | boolean | true \| false | - |
| onOpen | 下拉菜单打开时回调 | (() => void) | - | - |
| onClose | 下拉菜单关闭时回调 | (() => void) | - | - |
| onOverlayScroll | 下拉列表滚动时的回调 | (() => void) | - | - |
| gutterGap | 气泡卡片与触发器的间距 | number | - | - |
| innerRef | 提供辅助方法的内部引用 | Ref\ | - | - |
| invalid | 开启表单控件组件输入无效态 | boolean | true \| false | - |
| classNames | | CheckCascaderSemanticClassNames | - | - |
| styles | | CheckCascaderSemanticStyles | - | - |
## Type
### CheckCascaderDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | --------------------------------------------------------------------- | ----------------------- | ------------- | ------ |
| id | 选择项值,唯一 id | ReactText | - | - |
| title | 选项标题 | ReactNode | - | - |
| children | 下一级选项列表 | CheckCascaderDataItem[] | - | - |
| disabled | 是否禁用该节点(将禁用级联点击,展开,如果开启 checkbox,也将被禁用) | boolean | true \| false | false |
| isLeaf | 是否为叶子节点,当 children 为空数组也表示为叶子结点 | boolean | true \| false | - |
| checkable | 是否开启 checkbox 功能 | boolean | true \| false | - |
| disabledCheckbox | 是否禁用该节点 checkbox 功能 | boolean | true \| false | - |
| disabledCheckboxCascaded | 是否禁用该节点 checkbox 级联功能,禁用后只能用于展示勾选状态,无法进行操作 | boolean | true \| false | - |
### CheckCascaderItemEventData
> 继承自 CheckCascaderDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ------------------------------ | ---------------------------- | ------ | ------ |
| children | 下一级选项列表 | CheckCascaderItemEventData[] | - | - |
| raw | 关联用户传入的原始数据对象 | CheckCascaderDataItem | - | - |
| depth | 该节点的层级,从 0(顶层)开始 | number | - | - |
| parent | 该节点的父节点 | CheckCascaderItemEventData | - | - |
### PopperOverlayProps
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | ---------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| className | 弹层类名 | string | - | - |
| matchWidth | 自动计算匹配吸附元素的宽度与其一致 | boolean | true \| false | false |
| placement | 相对吸附元素的位置 | PopperPlacementEnum | "top" \| "bottom" \| "right" \| "left" \| "top-start" \| "top-end" \| "bottom-start" \| "bottom-end" \| "right-start" \| "right-end" \| "left-start" \| "left-end" \| "auto" \| "auto-start" \| "auto-end" | "bottom-start" |
| container | 指定 portal 的容器 | HTMLElement | - | - |
| disabledPortal | 禁用 portal | boolean | true \| false | false |
| arrow | 是否展示箭头 | boolean | true \| false | false |
# CheckSelect 多项选择器
弹出一个下拉菜单给用户进行部分选项选择的操作。
## 使用示例
### 基础用法
展示从全部备选项选出的部分选项
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Basic = () => {
const [data] = React.useState([
{ title: '手机', id: '1' },
{ title: '电脑', id: '2' },
{ title: '电视', id: '3' },
{ title: '平板', id: '4' },
{ title: '冰箱', id: '5' },
{ title: '洗衣机', id: '6' },
{ title: '空调', id: '7' },
{ title: '其它', id: '8' },
])
return (
<>
>
)
}
```
### 受控
```tsx
import Button from '@hi-ui/button'
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Controlled = () => {
const [value, setValue] = React.useState(['3'])
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
{
setValue(selectedId)
}}
/>
>
)
}
```
### 非受控
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Uncontrolled = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
{
console.log('onChange', selectedId)
}}
/>
>
)
}
```
### 清空选中项
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Clearable = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
>
)
}
```
### 展示全部已选项
设置后,选中内容超出宽度时会换行展示
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const TagInputWrap = () => {
const [data] = React.useState([
{ title: '手机', id: '1' },
{ title: '电脑', id: '2' },
{ title: '电视', id: '3' },
{ title: '平板', id: '4' },
{ title: '冰箱', id: '5' },
{ title: '洗衣机', id: '6' },
{ title: '空调', id: '7' },
{ title: '其它', id: '8' },
])
return (
<>
>
)
}
```
### 不同UI风格
UI风格包括线性、面性、无UI三种
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Appearance = () => {
const [value, setValue] = React.useState(['2'])
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
filled
{
console.log('CheckSelect onChange: ', value, targetItem)
setValue(value)
}}
/>
outline
{
console.log('CheckSelect onChange: ', value, targetItem)
setValue(value)
}}
/>
unset
{
console.log('CheckSelect onChange: ', value, targetItem)
setValue(value)
}}
/>
borderless
{
console.log('CheckSelect onChange: ', value, targetItem)
setValue(value)
}}
/>
contained
{
console.log('CheckSelect onChange: ', value, targetItem)
setValue(value)
}}
/>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Size = () => {
const [data] = React.useState([
{ title: '手机', id: '1' },
{ title: '电脑', id: '2' },
{ title: '电视', id: '3' },
{ title: '平板', id: '4' },
{ title: '冰箱', id: '5' },
{ title: '洗衣机', id: '6' },
{ title: '空调', id: '7' },
{ title: '其它', id: '8' },
])
return (
<>
xs
sm
md
lg
>
)
}
```
### 禁用状态
暂不可操作的状态
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Disabled = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: true },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: true },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
整体禁用
禁用某个选项
>
)
}
```
### 类型分组
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Group = () => {
const [value, setValue] = React.useState(['3'])
const [data] = React.useState([
{
groupId: 'redmi',
groupTitle: '红米手机',
children: [
{ title: '红米 5A', id: '3' },
{ title: '红米 6A', id: '2' },
{ title: '红米 note', id: '4' },
{ title: '红米 note8', id: '5' },
],
},
{
groupId: 'mi',
groupTitle: '小米电视',
children: [
{ title: '小米电视4A 60寸', id: '10' },
{ title: '小米电视E55A', id: '11' },
{ title: '小米电视E65A', id: '12' },
{ title: '小米电视4S', id: '13' },
{ title: '小米电视4C', id: '14' },
],
},
])
return (
<>
{
setValue(selectedId)
}}
/>
>
)
}
```
### 全选
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const CheckAll = () => {
const [value, setValue] = React.useState(['3'])
const [data] = React.useState([
{ title: '红米 5A', id: '3' },
{ title: '红米 6A', id: '2' },
{ title: '红米 note8', id: '5' },
{ title: '小米电视E65A', id: '12' },
{ title: '小米电视4S', id: '13' },
{ title: '小米电视4C', id: '14' },
])
return (
<>
{
setValue(selectedId)
}}
/>
>
)
}
```
### 带搜索
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Search = () => {
const [data] = React.useState([
{
id: 'up-1',
title: 'up',
},
{
id: '0',
title: '0',
},
{
id: '1',
title: '1',
},
{
id: '2',
title: '2',
},
])
return (
<>
>
)
}
```
### 清除搜索
关闭弹窗时清除搜索,默认不开启
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const ClearSearch = () => {
const [data] = React.useState([
{
id: 'up-1',
title: 'up',
},
{
id: '0',
title: '0',
},
{
id: '1',
title: '1',
},
{
id: '2',
title: '2',
},
])
return (
<>
>
)
}
```
### 创建选项
```tsx
import React from 'react'
import CheckSelect, { CheckSelectMergedItem } from '@hi-ui/check-select'
export const CreateItem = () => {
const [data, setData] = React.useState([
{
id: 'up-1',
title: 'up',
},
{
id: '0',
title: '0',
},
{
id: '1',
title: '1',
},
{
id: '2',
title: '2',
},
])
return (
<>
{
console.log('onCreate', item)
// setData([...data, item])
setData([item, ...data])
}}
data={data}
/>
>
)
}
```
### 异步加载搜索
备选项数量较大时,通过搜索选项关键词调取存储于服务端数据备选项的一个或多个
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const DataSource = () => {
const [data] = React.useState([
{
id: 'up-1',
title: 'up',
},
{
id: '0',
title: '0',
},
{
id: '1',
title: '1',
},
{
id: '2',
title: '2',
},
])
return (
<>
{
console.log('DataSource', keyword)
const url =
'https://www.fastmock.site/mock/eef9b373d82560f30585521549c4b6cb/hiui/api/list?keyword=' +
keyword
return fetch(url)
.then((response) => {
return response.json()
})
.then(function (res) {
return res.list
})
.catch((error) => {
console.error('DataSource', error)
return []
})
}}
/>
>
)
}
```
### 自定义回显展示
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const DisplayRender = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
{
console.log(item)
return (
{item.title}
({item.id})
)
}}
/>
>
)
}
```
### 自定义选项展示
可自定义选项的信息结构或样式
```tsx
import { CheckOutlined } from '@hi-ui/icons'
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const TitleRender = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
{
return (
{item.title}
{item.checked ? (
) : null}
)
}}
/>
>
)
}
```
### 吸底内容条
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const Footer = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
{
return (
Custom Footer
)
}}
/>
>
)
}
```
### 自定义头尾
```tsx
import React, { useState } from 'react'
import CheckSelect from '@hi-ui/check-select'
export const ExtraRender = () => {
const [data] = useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
custom header
}
renderExtraFooter={(CheckAllNode) => {
return (
custom title
{CheckAllNode}
custom footer
)
}}
/>
>
)
}
```
### 自定义筛选
通过 filterOption 可自定义搜索条件的算法
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const FilterOptions = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
// 注意 filterOption 是影响搜索渲染的,是完全受控的,useCallback 包裹可以减少无效的重渲染,提升性能
const filterOptionMemo = React.useCallback((keyword: string, item: any) => {
return item.id >= parseInt(keyword)
}, [])
return (
<>
>
)
}
```
### 拼音搜索
通过输入拼音搜索关键字
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
import { match } from 'pinyin-pro'
export const Pinyin = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边', id: '5' },
{ title: '办公', id: '6' },
])
// 注意 filterOption 是影响搜索渲染的,是完全受控的,useCallback 包裹可以减少无效的重渲染,提升性能
const filterOptionMemo = React.useCallback((keyword: string, item: any) => {
return !!match(item.title as string, keyword)
}, [])
return (
<>
>
)
}
```
### 大数据
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const VirtualList = () => {
const [data] = React.useState(() => {
const data: any[] = []
for (let i = 0; i < 5000; i++) {
const value = `${i.toString(36)}-${i}`
data.push({
id: value,
title: value,
disabled: i === 10,
})
}
return data
})
console.log('data', data)
return (
<>
v.id)}
placeholder="请选择品类"
searchPlaceholder="请输入搜索内容"
>
>
)
}
```
### 自定义空内容
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const EmptyContent = () => {
const [data] = React.useState([])
return (
<>
>
)
}
```
### 查看已选
只展示选中的选项
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
export const OnlyChecked = () => {
const [data] = React.useState([
{ title: '手机', id: '1' },
{ title: '电脑', id: '2' },
{ title: '电视', id: '3' },
{ title: '平板', id: '4' },
{ title: '冰箱', id: '5' },
{ title: '洗衣机', id: '6' },
{ title: '空调', id: '7' },
{ title: '其它', id: '8' },
])
return (
<>
>
)
}
```
### 带Tooltip提示
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
import Tooltip from '@hi-ui/tooltip'
import Checkbox from '@hi-ui/checkbox'
export const Tip = () => {
const [data] = React.useState([
{ title: '电视', id: '3', disabled: false },
{ title: '手机', id: '2' },
{ title: '笔记本', id: '4', disabled: false },
{ title: '生活周边超级长文案展示生活周边超级长文案展示', id: '5' },
{ title: '办公', id: '6' },
])
return (
<>
{
console.log(item)
return (
{item.title}
)
}}
/>
>
)
}
```
### 前后内置元素
将选择框与内置的其他元素组合使用
```tsx
import React from 'react'
import CheckSelect from '@hi-ui/check-select'
import { AppStoreOutlined, InfoCircleOutlined } from '@hi-ui/icons'
export const Addon = () => {
const [data] = React.useState([
{ title: '手机', id: '1' },
{ title: '电脑', id: '2' },
{ title: '电视', id: '3' },
{ title: '平板', id: '4' },
{ title: '冰箱', id: '5' },
{ title: '洗衣机', id: '6' },
{ title: '空调', id: '7' },
{ title: '其它', id: '8' },
])
return (
<>
}
suffix={}
/>
>
)
}
```
### 自定义触发器
```tsx
import React from 'react'
import { FilterOutlined } from '@hi-ui/icons'
import Button from '@hi-ui/button'
import Space from '@hi-ui/space'
import CheckSelect from '@hi-ui/check-select'
export const CustomRender = () => {
const [data] = React.useState([
{ title: '手机', id: '1' },
{ title: '电脑', id: '2' },
{ title: '电视', id: '3' },
{ title: '平板', id: '4' },
{ title: '冰箱', id: '5' },
{ title: '洗衣机', id: '6' },
{ title: '空调', id: '7' },
{ title: '其它', id: '8' },
])
return (
<>
只展示图标
}
overlay={{
placement: 'right-start',
}}
/>
展示选中内容
{
return (
e.stopPropagation()}>
{value.map((item, index) => (
{item.title}
))}
)
}}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对 Select 各元素进行细粒度的样式控制(含 Picker 的 root/container/panel 等及 option/optionGroup)
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import CheckSelect, { CheckSelectSemanticName } from '@hi-ui/check-select'
export const Semantic = () => {
const [data] = React.useState([
{
groupId: 'redmi',
groupTitle: '红米手机',
children: [
{ title: '红米 5A', id: '3' },
{ title: '红米 6A', id: '2' },
{ title: '红米 note', id: '4' },
{ title: '红米 note8', id: '5' },
],
},
{
groupId: 'mi',
groupTitle: '小米电视',
children: [
{ title: '小米电视4A 60寸', id: '10' },
{ title: '小米电视E55A', id: '11' },
{ title: '小米电视E65A', id: '12' },
{ title: '小米电视4S', id: '13' },
{ title: '小米电视4C', id: '14' },
],
},
])
const [selected, setSelected] = useState()
return (
<>
custom header
}
renderExtraFooter={() => 'custom footer'}
// @ts-ignore
overlay={{ flip: false }}
/>
(
setSelected(dataItem.title as CheckSelectSemanticName)}
onMouseLeave={() => setSelected(undefined)}
>
)}
/>
>
)
}
```
## Props
### CheckSelect Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| virtual | 设置 \`true\` 开启虚拟滚动 | boolean | true \| false | true |
| searchable | 是否可搜索(仅在 title 为字符串时支持) | boolean | true \| false | - |
| clearable | 是否可清空 | boolean | true \| false | true |
| onClear | 是否点击清理 tags | (() => void) | - | - |
| size | 自定义尺寸 | HiBaseSizeEnum | "xs" \| "sm" \| "md" \| "lg" | - |
| render | 自定义渲染节点的 title 内容 | ((item: CheckSelectItemEventData) => ReactNode) | - | - |
| displayRender | 自定义选择后触发器所展示的内容,只在 title 为字符串时有效 | ((option: CheckSelectItemEventData) => ReactNode) | - | - |
| placeholder | 触发器输入框占位符 | string | - | - |
| appearance | 设置展现形式 | CheckSelectAppearanceEnum | "line" \| "filled" \| "unset" \| "borderless" \| "contained" | - |
| label | 设置输入框 label 内容,仅在 appearance 为 contained 时生效 | ReactNode | - | - |
| searchMode | 节点搜索模式,仅在mode=normal模式下生效 | "filter" \| "highlight" | "filter" \| "highlight" | - |
| filterOption | 自定义搜索过滤器,仅在 searchable 为 true 时有效
第一个参数为输入的关键字,
第二个为数据项,返回值为 true 时将出现在结果项 | ((keyword: string, item: CheckSelectDataItem) => boolean) | - | - |
| dataSource | 异步加载数据 | UseDataSource\ | - | - |
| searchOnInit | 初始化时执行一次搜索,仅在 dataSource 不为空时有效 | boolean | true \| false | - |
| renderExtraFooter | 自定义下拉菜单底部渲染 | ((CheckAllNode?: ReactNode) => ReactNode) | - | - |
| renderExtraHeader | 自定义下拉菜单顶部渲染 | (() => ReactNode) | - | - |
| prefix | 选择框前置内容 | ReactNode | - | - |
| suffix | 选择框后置内容 | ReactNode | - | - |
| clearIcon | 自定义清除 tags 的 icon | ReactNode | - | - |
| onOpen | 面板打开时回调 | (() => void) | - | - |
| onClose | 面板关闭时回调 | (() => void) | - | - |
| showCheckAll | 是否开启全选功能 | boolean | true \| false | false |
| showOnlyShowChecked | 是否开启查看仅已选功能 | boolean | true \| false | false |
| checkedOnEntered | 按Enter键是否选中当前项 | boolean | true \| false | true |
| customRender | 自定义渲染选中的内容 | ReactNode \| ((option: CheckSelectItemEventData\[]) => ReactNode) | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| (option: CheckSelectItemEventData\[]) => ReactNode | - |
| tagInputProps | TagInput 参数设置 | TagInputMockProps | - | - |
| creatableInSearch | 是否开启创建选项 | boolean | true \| false | - |
| onItemCreate | 创建选项时触发 | ((item: CheckSelectMergedItem) => void) | - | - |
| showIndicator | 是否展示箭头 | boolean | true \| false | true |
| innerRef | 提供辅助方法的内部引用 | Ref\ | - | - |
| loading | 是否在加载中 | boolean | true \| false | - |
| disabled | 是否禁用 | boolean | true \| false | false |
| emptyContent | 设置选项为空时展示的内容 | ReactNode | - | - |
| loadingContent | 加载中时的提示 | ReactNode | - | - |
| showEmpty | 展示未搜索结果 | boolean | true \| false | - |
| optionWidth | 自定义下拉选项宽度 | Width\ | string \| number \| string & {} | - |
| overlayClassName | 下拉根元素的类名称 | string | - | - |
| keyword | 搜索关键字,searchable 为 true 时有效 | string | - | - |
| creatableInSearchVisible | 是否显示「创建选项」入口。为 false 时不显示。
不传(undefined)时保持兼容:只要有搜索词即显示创建入口。
Select/CheckSelect 会传入此 prop,实现「仅当无结果或关键字与结果无全匹配时显示」。 | boolean | true \| false | - |
| createTitle | 创建选项时展示的标题 | string | - | - |
| onCreate | 创建选项时触发回调 | ((keyword: string) => void) | - | - |
| onSearch | 搜索时触发回调 | ((keyword: string) => void) | - | - |
| clearSearchOnClosed | 是否在关闭时清除搜索 | boolean | true \| false | - |
| overlay | 自定义控制 popper 行为 | PopperOverlayProps | - | - |
| closeOnEsc | 开启 Esc 快捷键关闭 | boolean | true \| false | - |
| searchPlaceholder | 搜索的占位符 | string | - | - |
| visible | 控制气泡卡片的显示和隐藏(受控) | boolean | true \| false | - |
| onOverlayScroll | 下拉列表滚动时的回调 | (() => void) | - | - |
| gutterGap | 气泡卡片与触发器的间距 | number | - | - |
| invalid | 开启表单控件组件输入无效态 | boolean | true \| false | - |
| value | 设置当前选中值 | ReactText\[] | - | - |
| defaultValue | 设置当前选中值默认值 | ReactText\[] | - | - |
| onChange | 选中值改变时的回调
value: 所有选中项的 id 集合
changedItems: 变更的选项集合
checkedItems:所有选中项的选项集合 | ((value: ReactText\[], changedItems: CheckSelectDataItem\[], checkedItems: CheckSelectDataItem\[]) => void) | - | - |
| data | 选项数据 | CheckSelectMergedItem\[] | - | - |
| fieldNames | 设置 data 中 id, title, disabled, children 对应的 key | Record\ | - | "{} as any" |
| classNames | | CheckSelectSemanticClassNames | - | - |
| styles | | CheckSelectSemanticStyles | - | - |
## Type
### CheckSelectMergedItem
> CheckSelectDataItem | CheckSelectGroupDataItem
#### CheckSelectDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ----------------- | --------- | ------------- | ------ |
| id | 选择项值,唯一 id | ReactText | - | - |
| title | 选项标题 | ReactNode | - | - |
| disabled | 是否禁用该选项 | boolean | true \| false | false |
#### CheckSelectGroupDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | ---------- | --------------------- | ------ | ------ |
| groupTitle | 选项组标题 | ReactNode | - | - |
| children | 组选项列表 | CheckSelectDataItem[] | - | - |
### CheckSelectItemEventData
> 继承自 CheckSelectDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------ | ------------------------------ | ------------------------ | ------ | ------ |
| raw | 关联用户传入的原始数据对象 | CheckSelectDataItem | - | - |
| depth | 该节点的层级,从 0(顶层)开始 | number | - | - |
| parent | 该节点的组信息 | CheckSelectGroupDataItem | - | - |
### PopperOverlayProps
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | ---------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| className | 弹层类名 | string | - | - |
| matchWidth | 自动计算匹配吸附元素的宽度与其一致 | boolean | true \| false | true |
| placement | 相对吸附元素的位置 | PopperPlacementEnum | "top" \| "bottom" \| "right" \| "left" \| "top-start" \| "top-end" \| "bottom-start" \| "bottom-end" \| "right-start" \| "right-end" \| "left-start" \| "left-end" \| "auto" \| "auto-start" \| "auto-end" | "bottom-start" |
| container | 指定 portal 的容器 | HTMLElement | - | - |
| disabledPortal | 禁用 portal | boolean | true \| false | false |
| arrow | 是否展示箭头 | boolean | true \| false | false |
### UseDataSource
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ---------------------------------- | -------------------------------- | -------------------------------------------------- | ------------- |
| url | 请求的 url | string | - | - |
| method | 请求方法 | string | get \| post | get |
| data | post 请求时请求体参数 | object | - | - |
| params | url 查询参数 | object | - | - |
| headers | 请求头 | object | - | - |
| withCredentials | 上传请求时是否携带 cookie | boolean | true \| false | false |
| transformResponse | 成功时的回调,用于对数据进行预处理 | (response: object) => DataItem[] | - | - |
| onError | 请求发生异常的回调方法 | (error: object) => void | - | - |
| mode | 请求模式 | string | 'same-origin' \| 'cors' \| 'no-cors' \| 'navigate' | 'same-origin' |
# CheckTreeSelect 多选树形选择器
一种接收树形数据结构的多项选择器,为用户提供复杂数据展示的能力。
## 使用示例
### 基础用法
展示从全部备选项选出的部分选项
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const Basic = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
>
)
}
```
### 受控
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const Controlled = () => {
const [value, setValue] = React.useState(['0-0'])
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
{
setValue(checkedIds)
}}
>
>
)
}
```
### 非受控
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const Uncontrolled = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
>
)
}
```
### 回显模式
不同模式下,选中项的内容不一样,默认是 `ALL` 模式,无论父子节点,选中后就会展示。
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const CheckedMode = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
ALL(默认)
PARENT
CHILD
SEPARATE
>
)
}
```
### 禁用
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const Disabled = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
>
)
}
```
### 展示全部已选项
设置后,选中内容超出宽度时会换行展示
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const TagInputWrap = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
>
)
}
```
### 不同UI风格
UI风格包括线性、面性、无UI三种
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const Appearance = () => {
const [value, setValue] = React.useState(['0-0'])
const [data] = React.useState([
{
title: '手机类',
id: '0',
disabled: true,
children: [
{
title: 'Redmi系列',
id: '0-0',
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
filled
{
console.log('CheckTreeSelect onChange: ', value, options)
setValue(value)
}}
/>
outline
{
console.log('CheckTreeSelect onChange: ', value, options)
setValue(value)
}}
/>
unset
{
console.log('CheckTreeSelect onChange: ', value, options)
setValue(value)
}}
/>
borderless
{
console.log('CheckTreeSelect onChange: ', value, options)
setValue(value)
}}
/>
contained
{
console.log('CheckTreeSelect onChange: ', value, options)
setValue(value)
}}
/>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const Size = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
xs
sm
md
lg
>
)
}
```
### 清空选中项
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const Clearable = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
disabled: true,
children: [
{
title: 'Redmi系列',
id: '0-0',
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
{
console.log('CheckTreeSelect onChange: ', checkedIds, options)
}}
/>
>
)
}
```
### 带搜索
选项数量较大,不熟悉数据的结构关系情况下,用搜索关键词的方式快速定位
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const Searchable = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
disabled: true,
children: [
{
title: 'Redmi系列',
id: '0-0',
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
// 注意 filterOption 是影响搜索渲染的,是完全受控的,useCallback 包裹可以减少无效的重渲染,提升性能
const filterOptionMemo = React.useCallback((keyword: string, item: any) => {
console.log(keyword, item)
const match = (node: any) =>
typeof node.title === 'string' && node.title.indexOf(keyword) !== -1
const matchUp = (node: any) => {
let found = match(node)
const { children } = node
if (children && !found) {
found = children.some((item: any) => matchUp(item))
}
return found
}
return matchUp(item)
}, [])
const [keyword, setKeyword] = React.useState('小米')
return (
<>
highlight 仅高亮
{
console.log('CheckTreeSelect onChange: ', checkedIds, options)
}}
/>
filter 高亮并且过滤无关节点
{
console.log('CheckTreeSelect onChange: ', checkedIds, options)
}}
/>
filterOption 自定义搜索策略
{
console.log('CheckTreeSelect onChange: ', checkedIds, options)
}}
/>
>
)
}
```
### 异步加载数据
备选项数量较大时,通过搜索选项关键词调取存储于服务端的数据备选项
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const DataSource = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
{
return new Promise((resolve) => {
// 递归过滤所有嵌套子节点,保留匹配的分支
function filterTree(nodes: any[]): any[] {
return nodes
.map((node: any) => {
if (node.children) {
const filteredChildren = filterTree(node.children)
if (node.title.includes(keyword) || filteredChildren.length > 0) {
return { ...node, children: filteredChildren }
}
} else if (node.title.includes(keyword)) {
return node
}
return null
})
.filter(Boolean)
}
const filteredData = filterTree(data)
setTimeout(() => {
resolve(filteredData)
}, 1000)
})
}}
checkedMode="PARENT"
onChange={console.log}
/>
>
)
}
```
### 默认展开全部
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const DefaultExpandAll = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
disabled: true,
children: [
{
title: 'Redmi系列',
id: '0-0',
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
{
console.log('CheckTreeSelect onChange: ', checkedIds, options)
}}
/>
>
)
}
```
### 全选
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const CheckAll = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
>
)
}
```
### 大数据
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const VirtualList = () => {
const [data] = React.useState(() => {
// 模拟 10^4 个数据量
function dig(path = '0', level) {
const list: any = []
for (let i = 0; i < 5; i += 1) {
const id = `${path}-${i}`
const treeNode = {
title: id,
id,
children: [] as any[],
}
if (level > 0) {
treeNode.children = dig(id, level - 1)
}
list.push(treeNode)
}
return list
}
const treeData = dig('0', 4)
return treeData
})
return (
<>
>
)
}
```
### 自定义触发器
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const CustomRender = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
{
return (
v.title).join(',')} readOnly placeholder="请选择" />
)
}}
/>
>
)
}
```
### 前后内置元素
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
import { AppStoreOutlined, InfoCircleOutlined } from '@hi-ui/icons'
export const Addon = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
}
suffix={}
/>
>
)
}
```
### 查看已选
只展示选中的选项
```tsx
import React from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const OnlyChecked = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
>
)
}
```
### 自定义头尾
```tsx
import React, { useState } from 'react'
import CheckTreeSelect from '@hi-ui/check-tree-select'
export const ExtraRender = () => {
const [data] = useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
return (
<>
custom header
}
renderExtraFooter={() => custom footer
}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对 CheckTreeSelect 各元素进行细粒度的样式控制(含 Picker 的 root/container/panel 等及 tree)
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import CheckTreeSelect, { CheckTreeSelectSemanticName } from '@hi-ui/check-tree-select'
export const Semantic = () => {
const [data] = React.useState([
{
title: '手机类',
id: '0',
children: [
{
title: 'Redmi系列',
id: '0-0',
disabled: true,
children: [
{
id: '0-0-1',
title: 'Redmi K30',
},
{
id: '0-0-2',
title: 'Redmi K30 Pro',
},
{
id: '0-0-3',
title: 'Redmi 10X 5G',
},
{
id: '0-0-4',
title: 'Redmi Note 8',
},
{
id: '0-0-5',
title: 'Redmi 9',
},
{
id: '0-0-6',
title: 'Redmi 9A',
},
],
},
{
title: '小米手机',
id: '0-1',
children: [
{
id: '0-1-1',
title: '小米10 Pro',
},
{
id: '0-1-2',
title: '小米10',
},
{
id: '0-1-3',
title: '小米10 青春版 5G',
},
{
id: '0-1-4',
title: '小米MIX Alpha',
},
],
},
],
},
{
title: '电视',
id: '1',
children: [
{
title: '小米电视 大师 65英寸OLED',
id: '1-0',
},
{
title: 'Redmi 智能电视 MAX 98',
id: '1-1',
},
{
title: '小米电视4A 60英寸',
id: '1-2',
},
],
},
])
const [selected, setSelected] = useState()
return (
<>
custom header
}
renderExtraFooter={() => 'custom footer'}
// @ts-ignore
overlay={{ flip: false }}
/>
(
setSelected(dataItem.title as CheckTreeSelectSemanticName)}
onMouseLeave={() => setSelected(undefined)}
>
)}
/>
>
)
}
```
## Props
### CheckTreeSelect Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| data | 展示数据 | CheckTreeSelectDataItem\[] | - | \[] |
| fieldNames | 设置 data 中 id, title, disabled, children 对应的 key (3.0 新增) object - { title: 'title', id: 'id',disabled:'disabled', children: 'children'} | Record\ | - | "{} as any" |
| checkedMode | 多选数据交互时回填、回显模式
PARENT: 当所有子节点被选中时将只保留父节点
ALL: 所有被选中节点,不区分父子节点(不支持异步数据加载勾选checkbox)
CHILD: 仅显示子节点(不支持异步数据加载勾选checkbox)
SEPARATE:父子完全独立受控 | "ALL" \| "PARENT" \| "CHILD" \| "SEPARATE" | "ALL" \| "PARENT" \| "CHILD" \| "SEPARATE" | "ALL" |
| bordered | 是否有边框 | boolean | true \| false | - |
| disabled | 是否禁用 | boolean | true \| false | false |
| defaultExpandAll | 是否默认展开所有树节点 | boolean | true \| false | false |
| expandedIds | 展开的节点(受控) | ReactText\[] | - | - |
| defaultExpandedIds | 默认展开的节点(非受控) | ReactText\[] | - | \[] |
| onExpand | 节点被点击(展开/收起)时触发 | (() => void) | - | - |
| defaultValue | 默认选中项 (非受控) | ReactText\[] | - | \[] |
| value | 默认选中项 (受控) | ReactText\[] | - | - |
| displayRender | 自定义渲染 Input 中展示内容 | ((item: CheckTreeSelectDataItem) => ReactNode) | - | - |
| placeholder | 输入框占位 string - 请选择 | string | - | - |
| searchMode | 节点搜索模式,仅在mode=normal模式下生效 | "filter" \| "highlight" | "filter" \| "highlight" | - |
| filterOption | 自定义搜索过滤器,仅在 searchable 为 true 时有效
第一个参数为输入的关键字,
第二个为数据项,返回值为 true 时将出现在结果项 | ((keyword: string, item: CheckTreeSelectDataItem) => boolean) | - | - |
| render | 自定义渲染节点的 title 内容 | ((node: CheckTreeSelectItemEventData) => ReactNode) | - | - |
| onLoadChildren | 点击异步加载子项 | ((node: CheckTreeSelectItemEventData) => void \| Promise\) | (node: CheckTreeSelectItemEventData) => void \| Promise\ | - |
| emptyContent | 没有选项时的提示 | ReactNode | - | - |
| optionWidth | 自定义下拉选项宽度 | number | - | - |
| overlayClassName | 下拉根元素的类名称 (3.0 新增) | string | - | - |
| onChange | 选中时触发
checkedIds: 选中项 ID 集合
checkedNodes: 选中项数据项集合
targetNode: 当前操作节点,清空时为 null
checked: 当前操作是否为选中操作 | ((checkedIds: ReactText\[], options: { checkedNodes: CheckTreeSelectDataItem\[]; semiCheckedIds: ReactText\[]; targetNode: CheckTreeSelectItemEventData \| null; checked: boolean; }) => void) | (checkedIds: ReactText\[], options: { checkedNodes: CheckTreeSelectDataItem\[]; semiCheckedIds: ReactText\[]; targetNode: CheckTreeSelectItemEventData \| null; checked: boolean; }) => void | - |
| clearable | 是否可清空 | boolean | true \| false | - |
| onClear | 点击关闭按钮时触发 | (() => void) | - | - |
| appearance | 设置展现形式 | CheckTreeSelectAppearanceEnum | "line" \| "filled" \| "unset" \| "borderless" \| "contained" | - |
| label | 设置输入框 label 内容,仅在 appearance 为 contained 时生效 | ReactNode | - | - |
| virtual | 设置 \`true\` 开启虚拟滚动 | boolean | true \| false | - |
| showCheckAll | 是否开启全选功能 | boolean | true \| false | - |
| showOnlyShowChecked | 是否开启查看仅已选功能 | boolean | true \| false | false |
| tagInputProps | TagInput 参数设置 | TagInputMockProps | - | - |
| size | 设置尺寸 | HiBaseSizeEnum | "xs" \| "sm" \| "md" \| "lg" | - |
| customRender | 自定义触发器 | ReactNode \| ((option: CheckTreeSelectDataItem\[]) => ReactNode) | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| (option: CheckTreeSelectDataItem\[]) => ReactNode | - |
| prefix | 选择框前置内容 | ReactNode | - | - |
| suffix | 选择框后置内容 | ReactNode | - | - |
| showIndicator | 是否展示箭头 | boolean | true \| false | true |
| renderExtraHeader | 自定义下拉菜单顶部渲染 | (() => ReactNode) | - | - |
| renderExtraFooter | 自定义下拉菜单底部渲染 | (() => ReactNode) | - | - |
| loading | 是否在加载中 | boolean | true \| false | - |
| loadingContent | 加载中时的提示 | ReactNode | - | - |
| showEmpty | 展示未搜索结果 | boolean | true \| false | - |
| searchable | 是否可搜索 | boolean | true \| false | - |
| keyword | 搜索关键字,searchable 为 true 时有效 | string | - | - |
| creatableInSearch | 在搜索状态下是否可创建选项 | boolean | true \| false | - |
| creatableInSearchVisible | 是否显示「创建选项」入口。为 false 时不显示。
不传(undefined)时保持兼容:只要有搜索词即显示创建入口。
Select/CheckSelect 会传入此 prop,实现「仅当无结果或关键字与结果无全匹配时显示」。 | boolean | true \| false | - |
| createTitle | 创建选项时展示的标题 | string | - | - |
| onCreate | 创建选项时触发回调 | ((keyword: string) => void) | - | - |
| onSearch | 搜索时触发回调 | ((keyword: string) => void) | - | - |
| clearSearchOnClosed | 是否在关闭时清除搜索 | boolean | true \| false | - |
| overlay | 自定义控制 popper 行为 | PopperOverlayProps | - | - |
| closeOnEsc | 开启 Esc 快捷键关闭 | boolean | true \| false | - |
| searchPlaceholder | 搜索的占位符 | string | - | - |
| visible | 控制气泡卡片的显示和隐藏(受控) | boolean | true \| false | - |
| onOpen | 下拉菜单打开时回调 | (() => void) | - | - |
| onClose | 下拉菜单关闭时回调 | (() => void) | - | - |
| onOverlayScroll | 下拉列表滚动时的回调 | (() => void) | - | - |
| gutterGap | 气泡卡片与触发器的间距 | number | - | - |
| innerRef | 提供辅助方法的内部引用 | Ref\ | - | - |
| invalid | 开启表单控件组件输入无效态 | boolean | true \| false | - |
| classNames | | CheckTreeSelectSemanticClassNames | - | - |
| styles | | CheckTreeSelectSemanticStyles | - | - |
## Type
### CheckTreeSelectDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ---------------------------------------------------- | ------------------------- | ------------- | ------ |
| id | 节点唯一 id | ReactText | - | - |
| title | 节点标题 | ReactNode | - | - |
| children | 子级数据列表 | CheckTreeSelectDataItem[] | - | - |
| disabled | 是否禁用该节点 | boolean | true \| false | false |
| isLeaf | 是否为叶子节点,当 children 为空数组也表示为叶子结点 | boolean | true \| false | - |
### CheckTreeSelectItemEventData
> 继承自 CheckTreeSelectDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ------------------------------ | ------------------------------ | ------ | ------ |
| children | 该节点的子节点列表 | CheckTreeSelectItemEventData[] | - | - |
| raw | 关联用户传入的原始数据对象 | CheckTreeSelectDataItem | - | - |
| depth | 该节点的层级,从 0(顶层)开始 | number | - | - |
| parent | 该节点的父节点 | CheckTreeSelectGroupDataItem | - | - |
### PopperOverlayProps
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | ---------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| className | 弹层类名 | string | - | - |
| matchWidth | 自动计算匹配吸附元素的宽度与其一致 | boolean | true \| false | true |
| placement | 相对吸附元素的位置 | PopperPlacementEnum | "top" \| "bottom" \| "right" \| "left" \| "top-start" \| "top-end" \| "bottom-start" \| "bottom-end" \| "right-start" \| "right-end" \| "left-start" \| "left-end" \| "auto" \| "auto-start" \| "auto-end" | "bottom-start" |
| container | 指定 portal 的容器 | HTMLElement | - | - |
| disabledPortal | 禁用 portal | boolean | true \| false | false |
| arrow | 是否展示箭头 | boolean | true \| false | false |
# Checkbox 复选
复选是用来在一组平铺选项中同时选择 1 个以上的选项
## 使用示例
### 基础用法
展示所有备选项,数量不宜超出10个
```tsx
import React from 'react'
import Checkbox from '@hi-ui/checkbox'
export const Basic = () => {
return (
<>
复选框
>
)
}
```
### 禁用状态
```tsx
import React from 'react'
import Checkbox from '@hi-ui/checkbox'
export const Disabled = () => {
return (
<>
复选框
复选框
复选框
>
)
}
```
### 受控
```tsx
import React from 'react'
import Checkbox from '@hi-ui/checkbox'
import Button from '@hi-ui/button'
export const Controlled = () => {
const [checked, setChecked] = React.useState(false)
return (
<>
{
console.log('onChange', evt.target.checked)
setChecked(evt.target.checked)
}}
>
Checkbox
>
)
}
```
### 成组
```tsx
import React from 'react'
import Checkbox from '@hi-ui/checkbox'
export const Group = () => {
const CheckboxGroup = Checkbox.Group
const [data] = React.useState([
{
title: '手机',
id: 'Phone',
},
{
title: '电脑',
id: 'Computer',
},
{
title: '智能',
id: 'Intelli',
},
{
title: '出行',
id: 'Transfer',
disabled: true,
},
])
const [selectedList, setSelectedList] = React.useState(['Phone'])
return (
<>
{
console.log(value)
setSelectedList(value)
}}
/>
>
)
}
```
### 垂直样式
选项的另一种布局形式,视页面空间选用
```tsx
import React from 'react'
import Checkbox from '@hi-ui/checkbox'
export const Placement = () => {
const CheckboxGroup = Checkbox.Group
const [data] = React.useState([
{
title: '手机',
id: 'Phone',
},
{
title: '电脑',
id: 'Computer',
},
{
title: '智能',
id: 'Intelli',
},
{
title: '出行',
id: 'Transfer',
disabled: true,
},
])
const [selectedList, setSelectedList] = React.useState(['Phone'])
return (
<>
{
console.log(value)
setSelectedList(value)
}}
/>
>
)
}
```
### 全选
一次操作选中所有选项
```tsx
import React from 'react'
import Checkbox from '@hi-ui/checkbox'
export const CheckAll = () => {
const [data] = React.useState([
{
title: '手机',
id: 'Phone',
},
{
title: '电脑',
id: 'Computer',
},
{
title: '智能',
id: 'Intelli',
},
{
title: '出行',
id: 'Transfer',
},
])
const [selectedList, setSelectedList] = React.useState(['Phone'])
return (
<>
0 && selectedList.length < 4}
checked={selectedList.length === 4}
onChange={() => {
setSelectedList((prev) => {
return prev.length < 4 ? data.map(({ id }) => id) : []
})
}}
>
全选
{
console.log(value)
setSelectedList(value)
}}
/>
>
)
}
```
### 灵活布局
Checkbox 与 Grid 组件一起使用,可以实现灵活的布局
```tsx
import React from 'react'
import Checkbox from '@hi-ui/checkbox'
import Grid from '@hi-ui/grid'
export const Children = () => {
const { Row, Col } = Grid
const CheckboxGroup = Checkbox.Group
const [selectedList, setSelectedList] = React.useState([
'Phone',
'Intelligent',
])
return (
<>
{
console.log(value)
setSelectedList(value)
}}
>
手机
电脑
智能
出行
生态
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Checkbox, { CheckboxGroup } from '@hi-ui/checkbox'
export const Semantic = () => {
const [selected, setSelected] = useState<'root' | 'input' | 'icon' | 'text'>()
const [selectedList, setSelectedList] = React.useState(['Phone'])
return (
<>
普通用法
复选框
成组用法
{
setSelectedList(value)
}}
/>
{
return (
{
setSelected(dataItem.title as any)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Checkbox Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | ----------------------------------------- | ----------------------------------------------- | ------------- | ------ |
| autoFocus | 是否自动获取焦点 | boolean | true \| false | false |
| checked | 是否选中 | boolean | true \| false | - |
| defaultChecked | 是否默认选中 | boolean | true \| false | false |
| disabled | 是否禁用 | boolean | true \| false | - |
| indeterminate | 不全选的样式控制,优先级大于 checked | boolean | true \| false | false |
| name | checkbox 表单控件的名称,用于 form 提交 | string | - | - |
| value | checkbox 表单控件绑定的值,用于 form 提交 | ReactText | - | - |
| onChange | 值变化时的回调 | ((evt: ChangeEvent\) => void) | - | - |
| invalid | 开启表单控件组件输入无效态 | boolean | true \| false | - |
| classNames | | CheckboxSemanticClassNames | - | - |
| styles | | CheckboxSemanticStyles | - | - |
### CheckboxGroup Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------ | --------------------------------------------------------- | ------------------------------------ | -------------------------- | ------------ |
| placement | 排列方式 | CheckboxPlacementEnum | "vertical" \| "horizontal" | "horizontal" |
| data | 指定可选项 | CheckboxDataItem\[] | - | \[] |
| defaultValue | 默认选中的项 | ReactText\[] | - | \[] |
| disabled | 是否禁用 | boolean | true \| false | false |
| name | CheckboxGroup 下所有 input\[type="checkbox"] 的 name 属性 | string | - | - |
| value | 指定选中的项 | ReactText\[] | - | - |
| onChange | 值变化时的回调 | ((checkedIds: ReactText\[]) => void) | - | - |
| checkboxClassNames | 复选框的语义化类名 | CheckboxSemanticClassNames | - | - |
| checkboxStyles | 复选框的语义化样式 | CheckboxSemanticStyles | - | - |
| invalid | 开启表单控件组件输入无效态 | boolean | true \| false | - |
## Type
### CheckboxDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | --------------- | --------- | ------------- | ------ |
| id | 选项值,唯一 id | ReactText | - | - |
| title | 选项显示内容 | ReactNode | - | - |
| disabled | 是否禁用该选项 | boolean | true \| false | false |
# Collapse 折叠面板
将信息以折叠的形式收入面板,以节省空间,减少信息干扰,应用时打开
## 使用示例
### 基础用法
可以同时展开多个面板,对垂直空间没有特别限制
```tsx
import React from 'react'
import Collapse from '@hi-ui/collapse'
export const Basic = () => {
return (
<>
我是小米手机的内容
我是红米手机的内容
我是小米笔记本的内容
我是小米 AI 的内容
>
)
}
```
### 手风琴模式
一次仅展开一个面板,有效减少垂直空间的占用
```tsx
import React from 'react'
import Collapse from '@hi-ui/collapse'
import { IconButton } from '@hi-ui/icon-button'
import { EditOutlined } from '@hi-ui/icons'
export const Accordion = () => {
return (
<>
我是小米手机的内容
}
onClick={(evt) => evt.stopPropagation()}
effect
/>
}
>
我是红米手机的内容
我是小米笔记本的内容
我是小米 AI 的内容
>
)
}
```
### 箭头位置
指定箭头放置方式
```tsx
import React from 'react'
import Collapse from '@hi-ui/collapse'
import { PlusOutlined } from '@hi-ui/icons'
import { IconButton } from '@hi-ui/icon-button'
export const ArrowPlacement = () => {
return (
<>
我是小米手机的内容
我是红米手机的内容
我是小米笔记本的内容
}
onClick={(evt) => evt.stopPropagation()}
/>
}
>
我是小米 AI 的内容
>
)
}
```
### 带边框
```tsx
import React from 'react'
import Collapse from '@hi-ui/collapse'
export const bordered = () => {
return (
<>
我是小米手机的内容
我是红米手机的内容
我是小米笔记本的内容
我是小米 AI 的内容
>
)
}
```
### 自定义箭头
```tsx
import React from 'react'
import Collapse from '@hi-ui/collapse'
import { FolderFilled, FolderOpenFilled } from '@hi-ui/icons'
export const ArrowRender = () => {
const [activeId, setActiveId] = React.useState(['2'])
return (
<>
{
return (
{expanded ? : }
)
}}
>
我是小米手机的内容
我是红米手机的内容
我是小米笔记本的内容
我是小米 AI 的内容
>
)
}
```
### 设置标题内容
```tsx
import React from 'react'
import Collapse from '@hi-ui/collapse'
import { TabList } from '@hi-ui/tabs'
export const Title = () => {
const [xiaomiTabList] = React.useState([
{ tabId: '0', tabTitle: '小米10' },
{ tabId: '1', tabTitle: '小米11' },
{ tabId: '2', tabTitle: '小米12' },
])
const [xiaomiActiveId, setXiaomiActiveId] = React.useState('0')
return (
<>
{
evt.stopPropagation()
}}
activeId={xiaomiActiveId}
onChange={setXiaomiActiveId}
/>
}
id="1"
>
我是{xiaomiTabList.find((item) => item.tabId === xiaomiActiveId)?.tabTitle}
我是红米手机的内容
>
)
}
```
### 设置头部大小
```tsx
import React from 'react'
import Collapse from '@hi-ui/collapse'
export const Size = () => {
return (
<>
小尺寸
我是红米手机的内容
我是红米手机的内容
常规
我是红米手机的内容
我是红米手机的内容
大尺寸
我是红米手机的内容
我是红米手机的内容
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Collapse from '@hi-ui/collapse'
export const Semantic = () => {
const [selected, setSelected] = useState<
'root' | 'head' | 'icon' | 'titleContainer' | 'title' | 'extra' | 'contentWrapper' | 'content'
>()
return (
<>
额外内容}
style={{ overflow: 'unset' }}
classNames={{
root: 'my-collapse-panel__root',
head: 'my-collapse-panel__head',
icon: 'my-collapse-panel__icon',
titleContainer: 'my-collapse-panel__title-container',
title: 'my-collapse-panel__title',
extra: 'my-collapse-panel__extra',
contentWrapper: 'my-collapse-panel__content-wrapper',
content: 'my-collapse-panel__content',
}}
styles={{
[selected as string]: {
outline: '1px solid #ffbe0a',
},
...(selected === 'content'
? {
contentWrapper: {
overflow: 'unset',
},
}
: {}),
}}
>
这是面板内容
{
return (
{
setSelected(dataItem.title as any)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Collapse Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------------- | ----------------- | -------------------------------- | --------------------------- | ------------------ |
| accordion | 开启手风琴模式 | boolean | true \| false | false |
| defaultActiveId | 默认展开的面板 id | ReactText\[] | - | "\[] as string\[]" |
| activeId | 展开的面板 id | ReactText\[] | - | - |
| arrowPlacement | 箭头所在位置 | CollapseArrowPlacementEnum | "left" \| "right" | "right" |
| showArrow | 是否显示展开箭头 | boolean | true \| false | true |
| onChange | 切换时的回调 | ((ids: ReactText\[]) => void) | - | - |
| children | 折叠面板 | ReactNode | - | - |
| bordered | 是否开启带边框 | boolean | true \| false | true |
| arrowRender | 箭头渲染 | ((active: boolean) => ReactNode) | - | - |
| size | 设置头部大小 | Omit\ | Omit\ | - |
### CollapsePanel Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------ | ------------ | ------------------------------- | ------------- | ------ |
| id *(required)* | 面板唯一标识 | string | - | - |
| title *(required)* | 面板的标题 | ReactNode | - | - |
| extra | 额外元素 | ReactNode | - | - |
| disabled | 是否禁用面板 | boolean | true \| false | false |
| children | 面板的内容 | ReactNode | - | - |
| classNames | | CollapsePanelSemanticClassNames | - | - |
| styles | | CollapsePanelSemanticStyles | - | - |
# Counter 数字加减器
## 使用示例
### 基础用法
```tsx
import React from 'react'
import Counter from '@hi-ui/counter'
export const Basic = () => {
return (
<>
console.log('onChange', v)} />
>
)
}
```
### 不同UI风格
UI风格包括线性、面性两种
```tsx
import React from 'react'
import Counter from '@hi-ui/counter'
export const Appearance = () => {
return (
<>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import Counter from '@hi-ui/counter'
export const Size = () => {
return (
<>
>
)
}
```
### 受控
```tsx
import React from 'react'
import Counter from '@hi-ui/counter'
import Button from '@hi-ui/button'
export const Controlled = () => {
const [current, setCurrent] = React.useState(1)
return (
<>
{
console.log('onChange', v)
setCurrent(v)
}}
/>
>
)
}
```
### 自动聚焦
```tsx
import React from 'react'
import Counter from '@hi-ui/counter'
export const AutoFocus = () => {
return (
<>
console.log('onChange', v)} />
>
)
}
```
### 自定义步长
```tsx
import React from 'react'
import Counter from '@hi-ui/counter'
export const Step = () => {
return (
<>
console.log('onChange', v)} />
>
)
}
```
### 滚轮滑动
```tsx
import React from 'react'
import Counter from '@hi-ui/counter'
export const Wheel = () => {
return (
<>
console.log('onChange', v)}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Counter from '@hi-ui/counter'
export const Semantic = () => {
const [selected, setSelected] = useState<
'root' | 'content' | 'minus' | 'inputWrapper' | 'input' | 'plus'
>()
return (
<>
{
return (
{
setSelected(dataItem.title as any)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Counter Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------- | ---------------------------------------------------------- | ----------------------------------------------- | --------------------------------------------- | ------ |
| autoFocus | 开启自动聚焦 | boolean | true \| false | - |
| value | 设置当前值 | number \| null | null \| number | - |
| defaultValue | 设置默认值 | number \| null | null \| number | - |
| step | 每次改变值的大小 | number | - | - |
| min | 最小值 | number | - | - |
| max | 最大值 | number | - | - |
| disabled | 是否禁用 | boolean | true \| false | - |
| onChange | 值改变时的回调 | ((value: number \| null) => void) | (value: number \| null) => void | - |
| appearance | 设置展现形式 | "line" \| "filled" | "line" \| "filled" | - |
| size | 设置计数器尺寸 | CounterSizeEnum | Omit\ | - |
| changeOnWheel | 开启滑轮改值 | boolean | true \| false | - |
| formatter | 指定输入框展示值的格式 | ((value: string \| number) => string \| number) | (value: string \| number) => string \| number | - |
| parser | 指定从 formatter 里转换回数字的方式,和 formatter 搭配使用 | ((value: string \| number) => number) | (value: string \| number) => number | - |
| invalid | 开启表单控件组件输入无效态 | boolean | true \| false | - |
| classNames | | CounterSemanticClassNames | - | - |
| styles | | CounterSemanticStyles | - | - |
# DatePicker 日期选择器
用于接收日期和时间类型的容器。
## 使用示例
### 基础用法
以天为粒度,展示“YYYY-MM-DD”
```tsx
import React, { useState } from 'react'
import DatePicker from '@hi-ui/date-picker'
export const Basic = () => {
const [controlledValue, setControlledValue] = useState(new Date())
return (
<>
基础
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
带默认值
{
console.log('onChange', date, dateStr)
}}
/>
受控
{
console.log('onChange', date, dateStr)
setControlledValue(date as Date)
}}
/>
禁用
{
console.log('onChange', date, dateStr)
}}
/>
限制范围
{
console.log('onChange', date, dateStr)
}}
/>
>
)
}
```
### 不同UI风格
UI风格包括线性、面性两种
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
export const Appearance = () => {
return (
<>
Line
{
console.log('onChange', date, dateStr)
}}
/>
filled
{
console.log('onChange', date, dateStr)
}}
/>
unset
{
console.log('onChange', date, dateStr)
}}
/>
borderless
{
console.log('onChange', date, dateStr)
}}
/>
contained
{
console.log('onChange', date, dateStr)
}}
/>
{
console.log('onChange', date, dateStr)
}}
/>
>
)
}
```
### 年份 / 季度 / 月份 / 周
以年份 / 季度 / 月份 / 周为展示粒度
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
export const YearMonthWeek = () => {
return (
<>
年份
{
console.log('onChange', date, dateStr)
}}
/>
季度
{
console.log('onChange', date, dateStr)
}}
/>
月份
{
console.log('onChange', date, dateStr)
}}
/>
周
{/* 如果遇到周选择选值问题,尝试手动引入 import 'moment/locale/zh-cn' */}
{
console.log('onChange', date, dateStr)
}}
/>
>
)
}
```
### 展示周
仅在日期选择器中生效
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
export const ShowWeek = () => {
return (
<>
展示周
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
展示周-自定义内容
{
const { value, weekNum } = info
return weekNum ? 'W' + weekNum : value
}}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
>
)
}
```
### 自定义单元格内容
```tsx
import React from 'react'
import moment from 'moment'
import DayJs from 'dayjs'
import DatePicker from '@hi-ui/date-picker'
export const CellRender = () => {
return (
<>
年份
{
const { type, text } = info
return type === 'today' ? {text} : text
}}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
}}
/>
月份
{
const { type, text } = info
return type === 'today' ? {text} : text
}}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
}}
/>
周
{
const { value, weekNum } = info
return weekNum ? 'W' + weekNum : value
}}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
}}
/>
周范围
{
// console.log('format', value)
const lastDay = value.clone().endOf('month').date()
const startOfWeek = value.clone().startOf('week')
const endOfWeek = value.clone().endOf('week')
const week = value.clone().week()
const weekYear = value.clone().weekYear()
// 如果当前日期是当月第一天或者或者小于周一,并且周一不是当月第一天,则该周视为 B 周
if (
(value.date() === 1 || startOfWeek.date() > value.date()) &&
startOfWeek.date() !== 1
) {
return `${weekYear}-${week}B`
}
// 如果当前日期是当月最后一天或者大于周日,并且周日不是最后一天,则该周视为 A 周
if (
(value.date() === lastDay || value.date() > endOfWeek.date()) &&
endOfWeek.date() !== lastDay
) {
return `${weekYear}-${week}A`
}
return `${weekYear}-${week}`
}}
// 自定义渲染出 AB 周,逻辑:
// 在当前月周选择面板下,如果当月第一天位于第一行并且不是周一,则该周视为B周
// 如果当前月最后一天位于最后一行并且不是周日,则该周视为A周
cellRender={(cellInfo) => {
// console.log('cellInfo', cellInfo)
const { value, weekNum } = cellInfo
if (weekNum) {
// weekStartDate 周一日期
// renderDate 当前月日期
const { weekStartDate, renderDate } = cellInfo
// 当前周最后一天
const weekEndDate = weekStartDate?.clone().add(6, 'day')
if (
weekEndDate &&
renderDate &&
(weekEndDate?.month() > renderDate?.month() ||
weekEndDate?.year() > renderDate?.year()) &&
weekStartDate?.month() === renderDate?.month()
) {
return weekNum + 'A'
}
if (
weekStartDate &&
renderDate &&
(weekStartDate?.month() < renderDate?.month() ||
weekStartDate?.year() < renderDate?.year()) &&
weekEndDate?.month() === renderDate?.month()
) {
return weekNum + 'B'
}
return weekNum
} else {
return value
}
}}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
const _date = date as Date[]
const start = moment(_date?.[0])
const end = moment(_date?.[1])
const lastDay = end.clone().endOf('month').date()
// 如果开始日期是当月第一天并且不是周一,则该周视为 B 周
if (start.date() === 1 && start.clone().startOf('week').date() !== 1) {
console.log('start week', dateStr?.[0] + 'B')
}
// 如果当前日期是当月最后一天并且不是周末,则该周视为 A 周
if (end.date() === lastDay && end.clone().endOf('week').date() !== lastDay) {
console.log('end week', dateStr?.[1] + 'A')
}
}}
/>
>
)
}
```
### 日期时间
以时间点为粒度,展示“YYYY-MM-DD HH:mm:ss”
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
export const DateTime = () => {
return (
<>
基础用法
{
console.log('onChange', date, dateStr)
}}
/>
设置选择面板默认展示的时间
{
console.log('onChange', date, dateStr)
}}
/>
设置选择面板默认展示的开始和结束时间
{
console.log('onChange', date, dateStr)
}}
/>
>
)
}
```
### 范围
以天、周、月、季度、年等粒度展示一个时间的范围
```tsx
import React, { useState } from 'react'
import DatePicker from '@hi-ui/date-picker'
import DayJs from 'dayjs'
export const Range = () => {
const [dynamicSelectedValue, setDynamicSelectedValue] = useState('')
const [start, setStart] = useState([])
return (
<>
日期
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
年份
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
季度
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
月份
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
周
{/* 如果遇到周范围选择选值问题,尝试手动引入 import 'moment/locale/zh-cn' */}
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
日期时间范围
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
时间段快速选择
{
console.log('onChange', date, dateStr)
}}
/>
动态限制日期范围
{
if (dynamicSelectedValue) {
const timestampCurrent = new Date(val).getTime()
const timestampSelect = new Date(dynamicSelectedValue).getTime()
const range = 7 * 24 * 60 * 60 * 1000
return !(
timestampSelect - range < timestampCurrent &&
timestampCurrent < timestampSelect + range
)
}
return false
}}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
}}
onSelect={(val, isCompleted) => {
console.log(val, isCompleted)
setDynamicSelectedValue(isCompleted ? '' : val)
}}
onClear={() => {
setDynamicSelectedValue('')
}}
/>
动态限制日期时间范围
{
if (!date) {
setStart([])
}
}}
onSelect={(val, isCompleted, index = 0) => {
console.log('select', val, isCompleted, index)
start[index] = val
setStart([...start])
}}
disabledDate={(val, view, index) => {
// 如果还没有选择开始日期,不禁用任何日期
if (!start[0]) {
return false
}
const currentTime = new Date(val).getTime()
const startTime = new Date(start[0]).getTime()
const sixtyDays = 60 * 24 * 60 * 60 * 1000 // 60天的毫秒数
// 如果是选择第二个日期
if (index === 1) {
// 禁用超过开始日期一周范围的日期
return currentTime < startTime || currentTime > startTime + sixtyDays
}
// 如果是选择第一个日期且已经选择了结束日期
if (index === 0 && start[1]) {
const endTime = new Date(start[1]).getTime()
// 禁用导致日期范围超过一周的日期
return currentTime > endTime || endTime - currentTime > sixtyDays
}
return false
}}
/>
>
)
}
```
### 带快捷选项
将常用的日期或时间提炼成快捷项,节省操作成本
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
export const Shortcut = () => {
return (
<>
内置
{
console.log('onChange', date, dateStr)
}}
/>
自定义选择范围
{
console.log('onChange', date, dateStr)
}}
/>
>
)
}
```
### 日历面板
```tsx
import React, { useState } from 'react'
import DatePicker from '@hi-ui/date-picker'
import DayJs from 'dayjs'
export const Lunar = () => {
const [customValue, setCustomValue] = useState(new Date('2020/4/8'))
return (
<>
预置农历
{
console.log('onChange', date, dateStr)
}}
/>
自定义日期信息
{
// const date = DatePicker.format(currentDate, 'yyyy/M/D')
// const yesterday = DatePicker.format(today - 86400000, 'yyyy/M/D')
// const currentday = DatePicker.format(customValue, 'yyyy/M/D')
const date = DayJs(currentDate).format('yyyy/M/D')
const yesterday = DayJs(today - 86400000).format('yyyy/M/D')
if (date === '2020/4/8') {
return (
米
)
} else if (date === yesterday) {
return (
昨
)
} else {
return ''
}
}}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
setCustomValue(date as Date)
}}
/>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
export const Size = () => {
return (
<>
xs
{
console.log('onChange', date, dateStr)
}}
/>
sm
{
console.log('onChange', date, dateStr)
}}
/>
md
{
console.log('onChange', date, dateStr)
}}
/>
lg
{
console.log('onChange', date, dateStr)
}}
/>
>
)
}
```
### 自定义渲染页脚
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
import Button from '@hi-ui/button'
export const FooterRender = () => {
return (
<>
日期
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
footerRender={(action, onPick) => {
return (
)
}}
/>
日期时间
{
console.log('onChange', date, dateStr)
}}
showTime
onSelect={console.log}
footerRender={(sureActionContent, onPick) => (
{sureActionContent}
)}
/>
日期范围
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
footerRender={(action, onPick) => (
)}
/>
日期时间范围
(
{sureActionContent}
)}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
/>
>
)
}
```
### 自定义触发器
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
import Input from '@hi-ui/input'
export const CustomRender = () => {
return (
<>
日期
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
customRender={(data) => {
const date = new Date(data[0] ?? new Date())
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const formattedDate = `${year}-${month}-${day}`
return
}}
/>
日期范围
{
console.log('onChange', date, dateStr)
}}
defaultValue={[new Date(), new Date()]}
customRender={(data) => {
const date1 = new Date(data[0] ?? new Date())
const date2 = new Date(data[1] ?? new Date())
const year1 = date1.getFullYear()
const year2 = date2.getFullYear()
const month1 = (date1.getMonth() + 1).toString().padStart(2, '0')
const month2 = (date2.getMonth() + 1).toString().padStart(2, '0')
const day1 = date1.getDate().toString().padStart(2, '0')
const day2 = date2.getDate().toString().padStart(2, '0')
const formattedDateTime1 = `${year1}-${month1}-${day1}`
const formattedDateTime2 = `${year2}-${month2}-${day2}`
return (
)
}}
/>
>
)
}
```
### 前内置元素
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
import { AppStoreOutlined } from '@hi-ui/icons'
export const Addon = () => {
return (
Addon
{
console.log('onChange', date, dateStr)
}}
onSelect={console.log}
prefix={}
/>
)
}
```
### 选择确认
为 true 时,只有点击确认按钮才会触发值变化,暂不支持范围选择
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
export const NeedConfirm = () => {
return (
<>
日期选择
console.log('onChange', date, dateStr)}
onSelect={(date) => console.log('onSelect', date)}
onConfirm={(date) => console.log('onConfirm', date)}
/>
日期时间选择
console.log('onChange', date, dateStr)}
onSelect={(date) => console.log('onSelect', date)}
onConfirm={(date) => console.log('onConfirm', date)}
/>
>
)
}
```
### 设置时区偏移
UTC时间偏移量,单位为小时。例如:东八区传入 8,西五区传入 -5
```tsx
import React from 'react'
import DatePicker from '@hi-ui/date-picker'
import moment from 'moment'
export const UTCOffset = () => {
const [value, setValue] = React.useState(new Date())
const [utcOffset] = React.useState(1)
return (
<>
日期时间
{
console.log('onSelect', date)
}}
onChange={(date, dateStr) => {
console.log('onChange', date, dateStr)
setValue(date)
}}
// 禁用小于今天的时间
disabledDate={(current, view) => {
// 获取当前系统时区
const systemTimezone = moment().utcOffset()
// 获取 UTC 时间
const utcTime = moment().startOf('day').add(-systemTimezone, 'minutes').clone()
// 获取对应时区的时间
const offsetUtcToday = utcTime.add(utcOffset, 'hours').clone()
const isDisabled = current < offsetUtcToday.toDate()
// console.log(isDisabled, current, offsetUtcToday.toDate())
return isDisabled
}}
/>
系统时间:{value?.toLocaleString()}
UTC时间:{(value as Date)?.toUTCString()}
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对 DatePicker 各元素进行细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import DatePicker, { DatePickerSemanticName } from '@hi-ui/date-picker'
import Button from '@hi-ui/button'
export const Semantic = () => {
const [selected, setSelected] = useState()
return (
<>
{
return (
)
}}
/>
(
setSelected(dataItem.title as DatePickerSemanticName)}
onMouseLeave={() => setSelected(undefined)}
>
)}
/>
>
)
}
```
## Props
### DatePicker Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| type | 选择器类型 | DatePickerTypeEnum | "date" \| "daterange" \| "year" \| "month" \| "week" \| "quarter" \| "weekrange" \| "timeperiod" \| "yearrange" \| "monthrange" \| "quarterrange" | - |
| defaultValue | 默认显示的日期 | DatePickerValue \| DatePickerValue\[] | null \| string \| number \| Date \| DatePickerValue\[] | - |
| value | 日期 | DatePickerValue \| DatePickerValue\[] | null \| string \| number \| Date \| DatePickerValue\[] | - |
| minDate | 最小日期 | Date | - | - |
| maxDate | 最大日期 | Date | - | - |
| utcOffset | UTC时间偏移量,单位为小时。例如:东八区传入8,西五区传入-5 | number | - | - |
| disabled | 是否禁用 | boolean | true \| false | "false" |
| inputReadOnly | 设置输入框为只读 | boolean | true \| false | "false" |
| disabledDate | 不可选择的日期(返回true为不可选) | ((currentDate: Date, view: CalendarViewEnum, panelIndex?: number) => boolean) \| undefined | (currentDate: Date, view: CalendarViewEnum, panelIndex?: number \| undefined) => boolean | () => false |
| clearable | 是否可以清空 | boolean | true \| false | true |
| showTime | 是否在日期选择器中显示时间选择器,在使用时请注意 format 的设置。
传入对象时等价于开启时间选择,且可通过 \`defaultOpenValue\` 在未选择日期时指定时间列的默认展示(与 \`defaultPickerValue\` 独立,仅影响时间滚轮)。 | boolean \| { defaultOpenValue?: TimePickerValue \| TimePickerValue\[]; } \| undefined | false \| true \| { defaultOpenValue?: TimePickerValue \| TimePickerValue\[] \| undefined; } | false |
| timeInterval | 时间段的间隔,以分钟为单位 | number | - | 240 |
| format | 展示的日期格式,配置参考 \[moment.js]\(http\://momentjs.cn/docs/#/displaying/format/) | string \| ((date: Moment) => string) | string \| (date: Moment) => string | - |
| shortcuts | 快捷面板 | string\[] \| { title: string; range: (number \| Date)\[]; }\[] | string\[] \| { title: string; range: (number \| Date)\[]; }\[] | - |
| weekOffset | 周起始,默认周日做为第一列(3.3.0版本后,优化为根据中英文自动设置周起始) | number | - | "0" |
| hourStep | 小时步进 | number | - | 1 |
| minuteStep | 分钟步进 | number | - | 1 |
| secondStep | 秒钟步进 | number | - | 1 |
| placeholder | 输入框占位符 | string \| string\[] | string \| string\[] | - |
| altCalendar | 自定义日期中历法展示信息 | CalendarDataItem\[] | - | - |
| altCalendarPreset | 预置历法信息(支持中国农历和印度节假日) | DatePickerAltCalendarPresetEnum | "zh-CN" \| "id-ID" | - |
| dateMarkRender | 自定义日期的右上角标记 | ((currentDate: number, today: number) => ReactNode) | - | - |
| dateMarkPreset | 预置日期的右上角标记(休 \| 班) | string | - | - |
| disabledHours | 禁止选择的小时,仅在 showTime 开启时生效 | ((panel: TimePickerPanelType) => number\[]) \| number\[] | (panel: TimePickerPanelType) => number\[] \| number\[] | () => \[] |
| disabledMinutes | 禁止选择的分钟,仅在 showTime 开启时生效 | number\[] \| ((selectedHour: number, panel: TimePickerPanelType) => number\[]) | number\[] \| (selectedHour: number, panel: TimePickerPanelType) => number\[] | () => \[] |
| disabledSeconds | 禁止选择的秒数,仅在 showTime 开启时生效 | number\[] \| ((selectedHour: number, selectedMinute: number, panel: TimePickerPanelType) => number\[]) | number\[] \| (selectedHour: number, selectedMinute: number, panel: TimePickerPanelType) => number\[] | () => \[] |
| onSelect | 选择日期的回调函数,(data: 选中的 moment 日期对象, isCompleted: 是否选择完成,仅在范围选择下有效,panelIndex: 当前操作面板索引) => void | ((data: Date, isCompleted: boolean, panelIndex?: number) => void) \| undefined | (data: Date, isCompleted: boolean, panelIndex?: number \| undefined) => void | - |
| onChange | 选择后的回调,(date: 选中的日期,dateStr: 选中的日期字符串) => void | ((date: Date \| Date\[] \| null, dateStr: string \| string\[] \| null) => void) | (date: Date \| Date\[] \| null, dateStr: string \| string\[] \| null) => void | - |
| onPanelChange | 日期面板改变时的回调函数 | ((data: Date) => void) | - | - |
| appearance | 不同 UI 外观 | "line" \| "unset" \| "filled" \| "borderless" \| "contained" | "line" \| "unset" \| "filled" \| "borderless" \| "contained" | "line" |
| label | 设置输入框 label 内容,仅在 appearance 为 contained 时生效 | ReactNode | - | - |
| size | 不同尺寸 | HiBaseSizeEnum | "xs" \| "sm" \| "md" \| "lg" | "'md'" |
| overlay | 自定义控制弹出层 popper | PopperOverlayProps | - | - |
| invalid | 是否非法 | boolean | true \| false | false |
| onOpen | 面板打开时回调 | (() => void) | - | - |
| onClose | 面板关闭时回调 | (() => void) | - | - |
| onClear | 清空时回调 | (() => void) | - | - |
| cellRender | 自定义单元格内容 | ((colInfo: CalendarColInfo, date: Moment) => ReactNode) | - | - |
| footerRender | 自定义渲染页脚 | ((actionContents: ReactElement\>, onPick: (dates: (Date \| Moment \| null)\[], isShowPanel?: boolean) => void) => ReactNode) \| undefined | (actionContents: ReactElement\>, onPick: (dates: (Date \| Moment \| null)\[], isShowPanel?: boolean \| undefined) => void) => ReactNode | - |
| strideSelectMode | 跨月选择模式
'auto' 自动切换模式,跨月选择时自动切换到跨月的日期选择面板;
'fixed' 固定模式,不自动切换(仅周范围选择下生效) | "auto" \| "fixed" | "auto" \| "fixed" | "auto" |
| customRender | 自定义触发器 | ReactNode \| ((option: (Date)\[]) => ReactNode) | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| (option: (Date \| undefined)\[]) => ReactNode | - |
| prefix | 选择框前置内容 | ReactNode | - | - |
| needConfirm | 是否需要确认按钮,为 \false\ 时失去焦点即代表选择。日期时间范围选择默认为 \true\ | boolean | true \| false | "false" |
| onConfirm | 点击确认按钮的回调 | ((date: Date \| Date\[]) => void) | (date: Date \| Date\[]) => void | - |
| visible | 是否显示日期选择器 | boolean | true \| false | - |
| defaultPickerValue | 默认面板显示的日期,当用户没有传入或选择日期时,选择面板基于此值来显示日期 | DatePickerValue \| DatePickerValue\[] | null \| string \| number \| Date \| DatePickerValue\[] | - |
| showIndicator | 是否展示指示器 | boolean | true \| false | true |
| showWeek | 是否展示周,仅在 type 为 date 或 daterange 时生效 | boolean | true \| false | - |
| classNames | | DatePickerSemanticClassNames | - | - |
| styles | | DatePickerSemanticStyles | - | - |
## Type
### DatePickerValue
> Date | string | number
### CalendarDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------- | ------------ | --------------- | ------------- | ------ |
| date | 日期 | DatePickerValue | - | - |
| content | 描述内容 | string | - | - |
| highlighted | 是否高亮展示 | boolean | true \| false | false |
## FAQ
### 输入框中出现日期显示异常
如出现选择日期后,在输入框中出现日期显示异常,或者日期格式和原来不同的话,请确认 format 属性的格式是否正确
# Descriptions 描述列表
展示只读性字段,一般用于详情页的信息展示。
## 使用示例
### 基础用法
Descriptions 结合 Descriptions.Item 完成描述列表的动态配置
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
export const Basic = () => {
return (
<>
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
>
)
}
```
### 通过Data 数组配置
Descriptions 通过 data api 描述 Item 信息
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
export const Config = () => {
const data = [
{
label: '满江红',
value: '怒发冲冠',
},
{
label: '靖康耻,犹未雪',
value: '臣子恨,何时灭',
},
{
label: '驾长车',
value: '踏破贺兰山缺',
},
{
label: '壮志饥餐胡虏肉',
value: '笑谈渴饮匈奴血',
},
{
label: '待从头',
value: '收拾旧山河',
},
{
label: '朝天阙',
value: '结束',
},
]
return (
<>
>
)
}
```
### 超出展示省略号
Descriptions 配合 EllipsisTooltip 组件,形成超出展示省略号功能
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
import EllipsisTooltip from '@hi-ui/ellipsis-tooltip'
export const Ellipsis = () => {
const data = [
{
// 超出宽度限制才会展示,没有超出不展示
label: 满江红,
value: '怒发冲冠',
},
{
label: 靖康耻,犹未雪。,
labelWidth: 100,
value: '臣子恨,何时灭。臣子恨,何时灭。',
},
{
label: '驾长车',
value: '踏破贺兰山缺',
},
{
label: '壮志饥餐胡虏肉',
value: '笑谈渴饮匈奴血',
},
{
label: '待从头',
labelWidth: 100,
value: 收拾旧山河,收拾旧山河,收拾旧山河,收拾旧山河,
},
{
label: '朝天阙',
value: '结束',
},
]
return (
<>
>
)
}
```
### 带边框的
设置 `appearance` 控制描述列表组件的展现形态
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
export const Bordered = () => {
return (
<>
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
>
)
}
```
### label对齐方式
通过设置 `labelPlacement` 控制 label 的对齐方式
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
export const LabelPlacement = () => {
return (
<>
默认外形:右对齐
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
表格外形:右对齐
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
>
)
}
```
### 设置标签和内容对齐方式
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
import Preview from '@hi-ui/preview'
import { JpgColorful } from '@hi-ui/icons'
import Button from '@hi-ui/button'
export const ContentPosition = () => {
const [images] = React.useState([
'http://i1.mifile.cn/f/i/hiui/docs/card/pic_1.png',
'http://i1.mifile.cn/f/i/hiui/docs/card/pic_2.png',
'http://i1.mifile.cn/f/i/hiui/docs/card/pic_3.png',
])
const [visible, setVisible] = React.useState(false)
const [current, setCurrent] = React.useState(0)
return (
<>
>
)
}
```
### 自定义列数
支持一栏至四栏平均分布
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
export const Col = () => {
return (
<>
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
>
)
}
```
### 上下布局
支持 label 和 content 上下布局形式进行展示
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
export const Vertical = () => {
return (
<>
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
>
)
}
```
### 垂直带边框
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
export const VerticalBorder = () => {
return (
<>
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
1000000222201133
>
)
}
```
### 固定label宽度
根据实际情况配置label宽度,一个页面中label宽度应该保持一致
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
export const LabelWidth = () => {
return (
<>
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
张三
15311969622
北京天安门
100000000
100000022220
test
1000000222201133
>
)
}
```
### 设置大小
```tsx
import React from 'react'
import Descriptions from '@hi-ui/descriptions'
import Preview from '@hi-ui/preview'
import { JpgColorful } from '@hi-ui/icons'
export const Size = () => {
const [images] = React.useState([
'http://i1.mifile.cn/f/i/hiui/docs/card/pic_1.png',
'http://i1.mifile.cn/f/i/hiui/docs/card/pic_2.png',
'http://i1.mifile.cn/f/i/hiui/docs/card/pic_3.png',
])
const [visible, setVisible] = React.useState(false)
const [current, setCurrent] = React.useState(0)
return (
<>
md
第三方网点
主站
有效
某某有限公司
是
备注内容可能会非常长备注内容可能会非常长备注内容可能会非常长
{
setCurrent(0)
setVisible(true)
}}
/>
{
setCurrent(1)
setVisible(true)
}}
/>
{
setCurrent(2)
setVisible(true)
}}
/>
sm
第三方网点
主站
有效
某某有限公司
是
备注内容可能会非常长备注内容可能会非常长备注内容可能会非常长
{
setCurrent(0)
setVisible(true)
}}
/>
{
setCurrent(1)
setVisible(true)
}}
/>
{
setCurrent(2)
setVisible(true)
}}
/>
{
setVisible(false)
}}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Descriptions, { DescriptionsSemanticName } from '@hi-ui/descriptions'
export const Semantic = () => {
const [selected, setSelected] = useState()
return (
<>
张三
15311969622
北京天安门
100000000
100000022220
test
{
return (
{
setSelected(dataItem.title as DescriptionsSemanticName)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Descriptions Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------------- | --------------------------------------------------------------- | ------------------------------ | -------------------------- | ------------ |
| placement | 对齐方式,默认'horizontal' | DescriptionsPlacementEnum | "horizontal" \| "vertical" | "horizontal" |
| appearance | 描述样式,分为table样式和unset | DescriptionsAppearanceEnum | "table" \| "unset" | "unset" |
| column | 列数,表示一行包含DescriptionItems的数量 | number | - | 3 |
| data | 提供JS配置化的方式渲染单元模块 | DescriptionsItemProps\[] | - | - |
| fieldNames | 设置 data 中label, value, labelWidth, labelPlacement 对应的 key | HiBaseFieldNames | - | - |
| labelPlacement | label对齐方式 | DescriptionsLabelPlacementEnum | "left" \| "right" | "left" |
| labelWidth | label宽度 | ReactText | - | - |
| columnGap | 单元格列间距
注:在无边框场景下生效 | ReactText | - | - |
| size | 设置大小 | "md" \| "sm" | "md" \| "sm" | - |
| contentPosition | 在 horizontal 放置时,标签相对内容垂直对齐的方式 | ContentPosition | - | "top" |
| classNames | | DescriptionsSemanticClassNames | - | - |
| styles | | DescriptionsSemanticStyles | - | - |
### DescriptionsItem Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | ------------------------------- | ------------------------------ | ----------------- | ------ |
| colSpan | 包含列的数量 | number | - | - |
| span | @deprecated 请使用 colSpan 替代 | number | - | - |
| label | 内容标题 | ReactNode | - | - |
| labelWidth | label宽度 | ReactText | - | - |
| labelPlacement | label 对齐方式 | DescriptionsLabelPlacementEnum | "left" \| "right" | - |
| value | 每一项的内容 | ReactNode | - | - |
# Drawer 抽屉
模态对话框一般会中断当前任务流,在相对无信息干扰的环境下完成微型任务
## 使用示例
### 基础用法
```tsx
import React from 'react'
import Drawer from '@hi-ui/drawer'
import Button from '@hi-ui/button'
export const Basic = () => {
const [visible, setVisible] = React.useState(false)
return (
<>
setVisible(false)}
footer={
}
>
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
>
)
}
```
### 尺寸
```tsx
import React from 'react'
import Drawer, { DrawerProps } from '@hi-ui/drawer'
import Button from '@hi-ui/button'
export const Size = () => {
const [visible, setVisible] = React.useState(false)
const [size, setSize] = React.useState('sm')
return (
<>
sm
md
setVisible(false)}
footer={
}
>
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
>
)
}
```
### 无头抽屉
title 不设置任何内容开启无头模式
```tsx
import React from 'react'
import Drawer from '@hi-ui/drawer'
import Button from '@hi-ui/button'
export const Header = () => {
const [visible, setVisible] = React.useState(false)
return (
<>
setVisible(false)}>
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
>
)
}
```
### 标签页头部
```tsx
import React from 'react'
import Drawer from '@hi-ui/drawer'
import Button from '@hi-ui/button'
import { TabList } from '@hi-ui/tabs'
export const TabsHeader = () => {
const [visible, setVisible] = React.useState(false)
const [activeId, setActiveId] = React.useState('1')
const Content1 = () => {
return 内容1
}
const Content2 = () => {
return 内容2
}
const Content3 = () => {
return 内容3
}
return (
<>
}
visible={visible}
onClose={() => setVisible(false)}
footer={
}
>
{(() => {
if (activeId === '1') {
return
}
if (activeId === '2') {
return
}
if (activeId === '3') {
return
}
return null
})()}
>
)
}
```
### 无蒙层
```tsx
import React from 'react'
import Drawer from '@hi-ui/drawer'
import Button from '@hi-ui/button'
export const Mask = () => {
const [visible, setVisible] = React.useState(false)
return (
<>
setVisible(false)}
footer={
}
>
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
>
)
}
```
### 点击外部事件处理
常用于无蒙层模式下,切换列表项详情内容
```tsx
import React from 'react'
import Drawer from '@hi-ui/drawer'
import Button from '@hi-ui/button'
import Tree, { TreeDataItem } from '@hi-ui/tree'
export const OutsideClick = () => {
const [visible, setVisible] = React.useState(false)
const [data] = React.useState([
{
id: 1,
title: '小米',
children: [
{
id: 2,
title: '研发',
disabled: true,
children: [
{ id: 3, title: '后端', disabled: true },
{ id: 4, title: '运维' },
{ id: 5, title: '前端' },
],
},
{ id: 6, title: '产品' },
],
},
{
id: 11,
title: '大米',
children: [
{ id: 22, title: '可视化' },
{ id: 66, title: 'HiUI' },
],
},
])
const [currentData, setCurrentData] = React.useState()
const wrapperRef = React.useRef(null)
return (
<>
{
// console.log('node', node)
if (id) {
setVisible(true)
setCurrentData(node?.raw)
} else {
setVisible(false)
}
}}
/>
setVisible(false)}
// 点击列表外部内容时关闭抽屉
onOutsideClick={(e) => {
// console.log('target', e.target)
console.log('dom', wrapperRef.current?.contains(e.target as Element))
if (!wrapperRef.current?.contains(e.target as Element)) {
setVisible(false)
}
}}
footer={
}
>
{currentData?.title}
>
)
}
```
### 局部容器抽屉
\`container` 自定义渲染抽屉的容器
```tsx
import React from 'react'
import Drawer from '@hi-ui/drawer'
import Button from '@hi-ui/button'
export const Container = () => {
const [visible, setVisible] = React.useState(false)
const [container, setContainer] = React.useState(null)
return (
<>
setVisible(false)}
>
我是一段文字,也可以是表单、表格、步骤条等等
>
)
}
```
### 嵌套抽屉
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import Drawer from '@hi-ui/drawer'
export const Nested = () => {
const [visible, setVisible] = React.useState(false)
const [nestVisible, setNestVisible] = React.useState(false)
return (
<>
setVisible(false)}
>
我是一段文字,也可以是表单、表格、步骤条等等
setNestVisible(false)}
>
Nest我是一段文字,也可以是表单、表格、步骤条等等
>
)
}
```
### 顶部额外操作
```tsx
import React from 'react'
import Drawer from '@hi-ui/drawer'
import Button from '@hi-ui/button'
import { EditOutlined } from '@hi-ui/icons'
export const Extra = () => {
const [visible, setVisible] = React.useState(false)
return (
<>
我是大标题
}
appearance="text"
size="xs"
/>
}
visible={visible}
onClose={() => setVisible(false)}
>
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
>
)
}
```
### 出现方位
设置抽屉拉出的方向
```tsx
import React from 'react'
import Drawer from '@hi-ui/drawer'
import Button from '@hi-ui/button'
export const Placement = () => {
const [visible, setVisible] = React.useState(false)
const [placement, setPlacement] = React.useState('tpp')
return (
<>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setVisible(false)}
footer={
}
>
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Drawer, { DrawerSemanticName } from '@hi-ui/drawer'
import Button from '@hi-ui/button'
export const Semantic = () => {
const [selected, setSelected] = useState()
const [container, setContainer] = useState(null)
return (
<>
}
classNames={{
root: 'my-drawer__root',
overlay: 'my-drawer__overlay',
wrapper: 'my-drawer__wrapper',
header: 'my-drawer__header',
title: 'my-drawer__title',
close: 'my-drawer__close',
body: 'my-drawer__body',
footer: 'my-drawer__footer',
}}
styles={{
[selected as string]: {
outline: '1px solid #ffbe0a',
overflow: 'unset',
},
}}
>
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
我是一段文字,也可以是表单、表格、步骤条等等
{
return (
{
setSelected(dataItem.title as DrawerSemanticName)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
### 命令式 API
通过 Drawer.open / Drawer.close 以命令方式打开和关闭抽屉;支持 confirm/cancel;若需在抽屉内容中访问 React Context,请使用 Drawer.useDrawer
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import Drawer from '@hi-ui/drawer'
export const WithAPI = () => {
return (
<>
>
)
}
```
### Context 访问
可通过 Drawer.useDrawer 在使用 api 式调用时,访问外层 Context
```tsx
import React, { useContext, useState } from 'react'
import Button from '@hi-ui/button'
import Drawer from '@hi-ui/drawer'
export const Context = () => {
const [ThemeContext] = useState(() => React.createContext('light'))
const ThemeConsumer = () => {
const theme = useContext(ThemeContext)
return 当前主题: {theme}
}
const [drawer, contextHolder] = Drawer.useDrawer()
return (
将 contextHolder 放在 ThemeContext.Provider 内,抽屉内容区域可正常获取外部 Context
{contextHolder}
)
}
```
## Props
### Drawer Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | ----------------------------------------------------------- | ------------------------ | -------------------------------------- | ------ |
| title | 模态框标题 | ReactNode | - | - |
| footer | 自定义抽屉底部 | ReactNode | - | - |
| showMask | 是否显示蒙层 | boolean | true \| false | - |
| width | 自定义抽屉宽度,仅在 placement="left" \| "right" 有效 | string \| number | string \| number | - |
| height | 自定义抽屉高度,仅在 placement="bottom" \| "top" 有效 | string \| number | string \| number | - |
| size | 头部大小 | "sm" \| "md" | "sm" \| "md" | - |
| zIndex | 自定义css展示层级 | number | - | - |
| preload | 开启预加载渲染,用于性能优化,优先级小于 \`unmountOnClose\` | boolean | true \| false | - |
| unmountOnClose | 开启关闭时销毁,用于性能优化,优先级大于 \`preload\` | boolean | true \| false | - |
| onClose | 关闭事件触发时的回调 | (() => void) | - | - |
| container | 指定 portal 的容器 | HTMLElement \| null | null \| HTMLElement | - |
| placement | 设置唤起的方向 | DrawerPlacementEnum | "left" \| "right" \| "top" \| "bottom" | - |
| closeable | 是否展示右上角关闭按钮 | boolean | true \| false | - |
| onOutsideClick | 外界元素点击数触发 | ((evt: Event) => void) | - | - |
| closeIcon | 自定义关闭按钮 | ReactNode | - | - |
| disabledPortal | 禁用 portal | boolean | true \| false | - |
| visible | 是否弹出显示 | boolean | true \| false | - |
| closeOnEsc | 开启 Esc 快捷键关闭 | boolean | true \| false | - |
| maskClosable | 开启点击蒙层时关闭 | boolean | true \| false | - |
| classNames | | DrawerSemanticClassNames | - | - |
| styles | | DrawerSemanticStyles | - | - |
# Dropdown 下拉菜单
用来将菜单收起在下拉面板中,使用中唤起面板,有效节省空间
## 使用示例
### 基础用法
将一组同类的动作收起成为菜单,由一个操作入口展示使用
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
export const Basic = () => {
const [list] = React.useState([
{
id: 0,
title: '小米商城',
href: 'https://www.mi.com',
},
{
id: 1,
title: '菜单二',
},
{
id: 2,
title: '菜单三',
},
{
id: 3,
title: '菜单四',
},
{
id: 4,
title: '菜单五',
},
])
return (
<>
>
)
}
```
### 禁用状态
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
export const Disabled = () => {
const [list] = React.useState([
{
id: '1',
title: '菜单一',
},
{
id: '2',
title: '菜单二',
},
{
id: '3',
title: '菜单三',
},
{
id: '4',
title: '链接一',
href: 'https://www.mi.com',
},
])
return (
<>
>
)
}
```
### 分组
通过分隔线将选项进行分组划分
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
export const Group = () => {
const [list] = React.useState([
{
id: 0,
title: '小米商城',
href: 'https://www.mi.com',
},
{
id: 1,
title: '菜单二',
},
{
id: 2,
title: '菜单三',
},
{
id: 3,
title: '菜单四',
},
{
id: 4,
title: '菜单五',
},
{
id: 'divider',
split: true,
},
{
id: 6,
title: '小米商城',
href: 'https://www.mi.com',
disabled: true,
},
])
return (
<>
>
)
}
```
### 触发方式
不同触发方式呼出菜单
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
export const Trigger = () => {
const [list] = React.useState([
{
id: 0,
title: '小米商城',
href: 'https://www.mi.com',
},
{
id: 1,
title: '菜单二',
},
{
id: 2,
title: '菜单三',
},
{
id: 3,
title: '菜单四',
},
{
id: 4,
title: '菜单五',
},
{
id: 5,
title: '菜单六',
},
])
return (
<>
>
)
}
```
### 多级菜单
菜单项不属于同一级别,可分层级展开使用
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
export const MultiMenu = () => {
const [list] = React.useState([
{
id: '移动至',
title: '移动至',
children: [
{
id: '2019',
title: '2019',
children: [
{
id: 'Q1',
title: 'Q1',
children: [
{
id: '01',
title: '01',
},
{
id: '02',
title: '02',
},
{
id: '03',
title: '03',
},
],
},
{
id: 'Q2',
title: 'Q2',
disabled: true,
},
{
id: 'Q3',
title: 'Q3',
},
],
},
{
id: '2020',
title: '2020',
children: [
{
id: 'Q1',
title: 'Q1',
children: [
{
id: '01',
title: '01',
},
{
id: '02',
title: '02',
},
{
id: '03',
title: '03',
},
],
},
{
id: 'Q2',
title: 'Q2',
disabled: true,
},
{
id: 'Q3',
title: 'Q3',
},
],
},
],
},
{
id: '复制至',
title: '复制至',
children: [
{
id: '2019',
title: '2019',
children: [
{
id: 'Q1',
title: 'Q1',
disabled: true,
children: [
{
id: '01',
title: '01',
},
{
id: '02',
title: '02',
children: [
{
id: '02-01',
title: '02-01',
},
{
id: '02-02',
title: '02-02',
},
],
},
{
id: '03',
title: '03',
children: [
{
id: '03-01',
title: '03-01',
},
{
id: '03-02',
title: '03-02',
},
],
},
],
},
{
id: 'Q2',
title: 'Q2',
},
{
id: 'Q3',
title: 'Q3',
},
],
},
{
id: '2020',
title: '2020',
children: [
{
id: 'Q1',
title: 'Q1',
disabled: true,
children: [
{
id: '01',
title: '01',
},
{
id: '02',
title: '02',
children: [
{
id: '02-01',
title: '02-01',
},
{
id: '02-02',
title: '02-02',
},
],
},
{
id: '03',
title: '03',
children: [
{
id: '03-01',
title: '03-01',
},
{
id: '03-02',
title: '03-02',
},
],
},
],
},
{
id: 'Q2',
title: 'Q2',
},
{
id: 'Q3',
title: 'Q3',
},
],
},
],
},
{
id: '删除',
title: '删除',
},
])
return (
<>
>
)
}
```
### 弹出方位
下拉菜单可打开不同的方向,以应对页面边缘的遮盖问题
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
import Button from '@hi-ui/button'
export const Placement = () => {
const [list] = React.useState([
{
id: 0,
title: '小米商城',
href: 'https://www.mi.com',
},
{
id: 1,
title: '菜单二',
},
{
id: 2,
title: '菜单三',
},
{
id: 3,
title: '菜单四',
},
{
id: 4,
title: '菜单五',
},
])
return (
<>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
)
}
```
### 按钮用法
操作入口以 Button 样式展示,强调重要操作
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
import message from '@hi-ui/message'
export const Type = () => {
const [list] = React.useState([
{
id: 0,
title: '小米商城',
href: 'https://www.mi.com',
},
{
id: 1,
title: '菜单二',
},
{
id: 2,
title: '菜单三',
},
{
id: 3,
title: '菜单四',
},
{
id: 4,
title: '菜单五',
},
{
id: 5,
title: '菜单六',
},
])
return (
<>
{
message.open({ title: '点击左侧按钮' })
}}
/>
>
)
}
```
### 自定义触发按钮
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
import { Tooltip } from '@hi-ui/tooltip'
import { Avatar } from '@hi-ui/avatar'
export const TriggerButton = () => {
const [list] = React.useState([
{
id: 0,
title: '小米商城',
href: 'https://www.mi.com',
},
{
id: 1,
title: '菜单二',
},
{
id: 2,
title: '菜单三',
},
{
id: 3,
title: '菜单四',
},
{
id: 4,
title: '菜单五',
},
{
id: 5,
title: '菜单六',
},
{
id: 6,
title: '菜单七',
},
])
return (
<>
>
)
}
```
### 带Icon
```tsx
import React from 'react'
import Dropdown from '@hi-ui/dropdown'
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@hi-ui/icons'
export const Icon = () => {
const [list] = React.useState([
{
id: 0,
title: (
添加
),
},
{
id: 1,
title: (
编辑
),
},
{
id: 2,
title: (
删除
),
},
])
return (
<>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Dropdown, { DropdownSemanticName } from '@hi-ui/dropdown'
export const Semantic = () => {
const [selected, setSelected] = useState()
const [list] = React.useState([
{
id: 0,
title: '小米商城',
href: 'https://www.mi.com',
},
{
id: 1,
title: '菜单二',
},
{
id: 2,
title: '菜单三',
},
{
id: 3,
title: '菜单四',
},
{
id: 4,
title: '菜单五',
},
])
return (
<>
{
return (
{
setSelected(dataItem.title as DropdownSemanticName)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Dropdown Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------- | ------ |
| title | 下拉菜单显示标题的内容 | ReactNode | - | - |
| data | 下拉菜单数据项 | DropdownDataItem\[] | - | \[] |
| fieldNames | 设置data 中id, title, href, target, disabled, split 等属性对应的 key | HiBaseFieldNames | - | - |
| width | 设置下拉面板宽度 | number | - | - |
| type | 下拉菜单按钮类型 | "button" \| "text" \| "group" | "button" \| "text" \| "group" | "text" |
| onButtonClick | 点击左侧按钮的回调,仅在 type 为 group 时有效 | ((event: MouseEvent\) => void) | - | - |
| onClick | 点击后的回调 | ((id: ReactText, item: DropdownDataItem) => void) | - | - |
| overlayClassName | 下拉根元素的类名称 | string | - | - |
| children | 自定义下拉菜单触发按钮
注意:自定义按钮需要支持 ref 获取元素 dom 引用 以及 trigger 对应的事件:
hover: onMouseEnter \ onMouseLeave
click: onClick
contextmenu: onContextMenu | ReactNode | - | - |
| overlay | 自定义控制 下拉 popper 行为 | PopperOverlayProps | - | - |
| size | 设置大小 | Omit\ | Omit\ | "lg" |
| trigger | 下拉菜单触发方式 | DropdownTriggerActionEnum \| DropdownTriggerActionEnum\[] | "click" \| "contextmenu" \| "hover" \| DropdownTriggerActionEnum\[] | - |
| disabled | 是否禁用下拉菜单 | boolean | true \| false | - |
| classNames | | DropdownSemanticClassNames | - | - |
| styles | | DropdownSemanticStyles | - | - |
## Type
### DropdownDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | --------------------------------------------- | --------- | ----------------------------------------------- | ------ |
| title | 标题的内容 | ReactNode | - | - |
| id | 唯一标识 id | ReactText | - | - |
| disabled | 是否禁用 | boolean | true \| false | false |
| href | 点击跳转的路径 | string | - | - |
| target | 同 a 标签的 target 属性,仅在设置 href 后有效 | string | ︎'\_self' \| '\_blank' \| '\_parent' \| '\_top' | - |
| split | 是否在其底部建立分隔线 | boolean | ︎true \| false | false |
### PopperOverlayProps
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------------- | ---------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| className | 弹层类名 | string | - | - |
| matchWidth | 自动计算匹配吸附元素的宽度与其一致 | boolean | true \| false | false |
| placement | 相对吸附元素的位置 | PopperPlacementEnum | "top" \| "bottom" \| "right" \| "left" \| "top-start" \| "top-end" \| "bottom-start" \| "bottom-end" \| "right-start" \| "right-end" \| "left-start" \| "left-end" \| "auto" \| "auto-start" \| "auto-end" | "bottom-start" |
| container | 指定 portal 的容器 | HTMLElement | - | - |
| disabledPortal | 禁用 portal | boolean | true \| false | false |
| arrow | 是否展示箭头 | boolean | true \| false | false |
# EllipsisTooltip 文字超出提示
文字个数超出后展示省略号,鼠标悬停时出现全部描述。
## 使用示例
### 基础用法
```tsx
import React from 'react'
import EllipsisTooltip from '@hi-ui/ellipsis-tooltip'
export const Basic = () => {
const textOverview = '学而时习之,不亦说乎?有朋自远方来,不亦乐乎?人不知而不愠,不亦君子乎?'
return (
<>
没有超出
这段文字没有超出限制时,不会出现提示
超出宽度限制
{textOverview},
}}
>
{textOverview}
>
)
}
```
### 多行省略
```tsx
import React from 'react'
import EllipsisTooltip from '@hi-ui/ellipsis-tooltip'
export const MultiplyLine = () => {
const textOverview =
'【译】孔子说:“学习并且不断温习,不也很愉快吗?远方来了朋友,不也很快乐吗?人家不了解我,我也不怨恨,不也是君子吗?”,【译】孔子说:“学习并且不断温习,不也很愉快吗?远方来了朋友,不也很快乐吗?人家不了解我,我也不怨恨,不也是君子吗?”'
return (
<>
超出 3 行(tooltip 内容过多可设置样式换行)
{textOverview},
}}
>
{textOverview}
>
)
}
```
### 超出字数省略
```tsx
import React from 'react'
import EllipsisTooltip from '@hi-ui/ellipsis-tooltip'
export const MaxTextCount = () => {
const textOverview = '学而时习之,不亦说乎?有朋自远方来,不亦乐乎?人不知而不愠,不亦君子乎?'
return (
<>
没有超出
学而时习之
文字超出 20 个字符时
{textOverview},
}}
>
{textOverview}
>
)
}
```
## Props
### EllipsisTooltip Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------- | ------------------------------------------------- | ---------------------- | ------ | ------ |
| numberOfLines | 超出行数展示省略号,children 是 string 类型时有效 | number | - | 1 |
| maxTextCount | 最大文字展示,children 是 string 类型时有效 | number | - | 0 |
| tooltipProps | tooltip 属性收敛 | Partial\ | - | - |
# EmptyState 空状态
指当前场景没有对应的数据内容,呈现出的一种状态。
## 使用示例
### 基础用法
```tsx
import React from 'react'
import EmptyState from '@hi-ui/empty-state'
export const Basic = () => {
return (
<>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import EmptyState from '@hi-ui/empty-state'
export const Size = () => {
return (
<>
>
)
}
```
### 带内容
```tsx
import React from 'react'
import EmptyState from '@hi-ui/empty-state'
import { Button } from '@hi-ui/button'
export const WithContent = () => {
return (
<>
>
)
}
```
### 自定义
```tsx
import React from 'react'
import EmptyState, {
EMPTY_STATE_IMAGE_NO_RESULT,
EMPTY_STATE_IMAGE_SERVICE_ERROR,
EMPTY_STATE_IMAGE_NO_ACCESS,
EMPTY_STATE_IMAGE_404,
EMPTY_STATE_IMAGE_NO_OPEN,
EMPTY_STATE_IMAGE_NO_NETWORK,
EMPTY_STATE_IMAGE_NO_LAN,
} from '@hi-ui/empty-state'
export const Custom = () => {
return (
<>
>
)
}
```
### 彩色图标
```tsx
import React from 'react'
import EmptyState, {
EMPTY_STATE_IMAGE_NO_MESSAGE_COLORFUL,
EMPTY_STATE_IMAGE_NO_RESULT_COLORFUL,
EMPTY_STATE_IMAGE_NO_COLLECTION_COLORFUL,
EMPTY_STATE_IMAGE_NO_ACCESS_COLORFUL,
EMPTY_STATE_IMAGE_NO_NETWORK_COLORFUL,
EMPTY_STATE_IMAGE_NO_OPEN_COLORFUL,
EMPTY_STATE_IMAGE_404_COLORFUL,
EMPTY_STATE_IMAGE_SERVICE_ERROR_COLORFUL,
EMPTY_STATE_IMAGE_PAGE_ERROR_COLORFUL,
EMPTY_STATE_IMAGE_SUCCESS_COLORFUL,
EMPTY_STATE_IMAGE_ERROR_COLORFUL,
EMPTY_STATE_IMAGE_WARNING_COLORFUL,
EMPTY_STATE_IMAGE_NO_DATA_COLORFUL,
EMPTY_STATE_IMAGE_JUMP_COLORFUL,
EMPTY_STATE_IMAGE_CHART_NO_DATA_COLORFUL,
} from '@hi-ui/empty-state'
export const Colorful = () => {
return (
<>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import EmptyState, { EmptyStateSemanticName } from '@hi-ui/empty-state'
export const Semantic = () => {
const [selected, setSelected] = useState()
return (
<>
这里是自定义内容区域
{
return (
{
setSelected(dataItem.title as EmptyStateSemanticName)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### EmptyState Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | --------------------------------------------- | ---------------------------- | --------------------------- | ------ |
| indicator | 指示器图标,如果是字符串将被设置为 Img 的 src | ReactNode | - | - |
| title | 空状态的标题 | ReactNode | - | - |
| size | 图标尺寸 | EmptyStateSizeEnum | Omit\ | - |
| classNames | | EmptyStateSemanticClassNames | - | - |
| styles | | EmptyStateSemanticStyles | - | - |
# FileSelect 文件选择器
用于选择文件。
## 使用示例
### 基础用法
```tsx
import React from 'react'
import FileSelect from '@hi-ui/file-select'
export const Basic = () => {
return (
<>
Upload
>
)
}
```
## Props
### FileSelect Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------- | ------------------ | ----------------------------------- | --------------------------------- | ------ |
| className | 组件的注入选择器类 | string | - | - |
| style | 组件的注入样式 | CSSProperties | - | - |
| accept | 接受的上传文件类型 | string | - | - |
| disabled | 是否禁用 | boolean | true \| false | - |
| multiple | 是否支持批量上传 | boolean | true \| false | - |
| onSelect | 选择上传的事件 | ((files: FileList \| null) => void) | (files: FileList \| null) => void | - |
| children | 自定义触发器 | ReactNode | - | - |
# Filter 筛选
多个维度筛选
## 使用示例
### 基础用法
一般作为筛选场景,作为筛选项
```tsx
import React from 'react'
import Filter from '@hi-ui/filter'
export const Basic = () => {
const [dataStore] = React.useState([
{
id: 1,
title: '小米商城',
},
{
id: 2,
title: '米家有品',
},
{
id: 3,
title: '京东商城',
},
{
id: 4,
title: '天猫淘宝',
},
{
id: 5,
title: '创新渠道',
},
{
id: 6,
title: '线下KA',
},
{
id: 7,
title: '线下KA1',
},
{
id: 8,
title: '线下KA2',
},
{
id: 9,
title: '线下KA3',
},
{
id: 10,
title: '线下KA4',
},
])
const [dataColor] = React.useState([
{
id: 1,
title: '深空',
},
{
id: 2,
title: '白色',
},
{
id: 3,
title: '亮黑色',
},
{
id: 4,
title: '金色',
},
])
return (
<>
{
console.log('value', value)
}}
/>
{
console.log('value', value)
}}
/>
>
)
}
```
### 级联选择
一般作为筛选场景,作为筛选项组合,每个级别之间有联动
```tsx
import React from 'react'
import Filter from '@hi-ui/filter'
export const Cascade = () => {
return (
<>
>
)
}
```
### 受控
```tsx
import React from 'react'
import Filter from '@hi-ui/filter'
export const Controlled = () => {
const [value, setValue] = React.useState([2, 21])
const data = [
{
id: 1,
title: '小米商城',
children: [
{
id: 11,
title: '小米商城',
},
{
id: 12,
title: '米家优品',
disabled: true,
},
],
},
{
id: 2,
title: '米家有品',
children: [
{
id: 21,
title: '五彩城店',
children: [
{
id: '小米9',
title: '小米9',
},
{
id: '小米MIXS',
title: '小米MIXS',
},
{
id: '小米8',
title: '小米8',
},
],
},
{
id: 22,
title: '清河店',
},
{
id: 23,
title: '西三旗店',
},
],
},
{
id: 3,
title: '京东商城',
children: [
{
id: 31,
title: '小米直营',
children: [
{
id: '线下KA',
title: '线下KA',
},
],
},
],
},
]
return (
<>
{
console.log('onChange', ids, targetItem)
setValue(ids)
}}
data={data}
/>
>
)
}
```
### 下划线
```tsx
import React from 'react'
import Filter from '@hi-ui/filter'
export const Underlined = () => {
return (
<>
>
)
}
```
### 设置选中时的形状
```tsx
import React from 'react'
import Filter from '@hi-ui/filter'
export const Appearance = () => {
const [dataStore] = React.useState([
{
id: 1,
title: '小米商城',
},
{
id: 2,
title: '米家有品',
},
{
id: 3,
title: '京东商城',
},
{
id: 4,
title: '天猫淘宝',
},
{
id: 5,
title: '创新渠道',
},
{
id: 6,
title: '线下KA',
},
{
id: 7,
title: '线下KA1',
},
{
id: 8,
title: '线下KA2',
},
{
id: 9,
title: '线下KA3',
},
{
id: 10,
title: '线下KA4',
},
])
const [dataColor] = React.useState([
{
id: 1,
title: '深空',
},
{
id: 2,
title: '白色',
},
{
id: 3,
title: '亮黑色',
},
{
id: 4,
title: '金色',
},
])
return (
<>
link
{
console.log('value', value)
}}
/>
{
console.log('value', value)
}}
/>
filled
{
console.log('value', value)
}}
/>
{
console.log('value', value)
}}
/>
>
)
}
```
## Props
### Filter Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------- | ----------------------------------------------------- | ----------------------------------------------------------- | ------------------ | ------ |
| appearance | 筛选表头选择时形状 | "link" \| "filled" | "link" \| "filled" | "link" |
| showUnderline | 是否显示下划线 | boolean | true \| false | false |
| labelWidth | 筛选标题宽度 | number | - | - |
| label | 筛选标题列表 | ReactText\[] | - | - |
| data | 筛选选项数据 | FilterDataItem\[] | - | - |
| fieldNames | 设置 data 中 id, title, disabled, children 对应的 key | HiBaseFieldNames | - | - |
| defaultValue | 默认选中项的值 | ReactText\[] | - | - |
| value | 被选中项的值 | ReactText\[] | - | - |
| onChange | 选择时的回调函数, value 表示选中项的 ID 集合 | ((value: ReactText\[], targetItem: FilterDataItem) => void) | - | - |
## Type
### FilterDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | --------------------- | ---------------- | ------------- | ------ |
| title | 选项的展示内容 | string | - | - |
| id | 选项对应的值,唯一 id | string | - | - |
| disabled | 是否禁用 | boolean | true \| false | false |
| children | 级联筛选项列表 | FilterDataItem[] | - | - |
# Form 表单
用来收集数据的组件集合
## 使用示例
### 基础用法
```tsx
import React from 'react'
import Form from '@hi-ui/form'
import Input from '@hi-ui/input'
export const Basic = () => {
const FormItem = Form.Item
return (
<>
>
)
}
```
### 对齐方式
表单项较少,对应标题字数易对齐工整
```tsx
import React from 'react'
import Form, { FormHelpers, FormProps } from '@hi-ui/form'
import Input from '@hi-ui/input'
import Radio from '@hi-ui/radio'
export const LabelPlacement = () => {
const FormItem = Form.Item
const FormSubmit = Form.Submit
const RadioGroup = Radio.Group
const formRef = React.useRef(null)
const [labelPlacement, setLabelPlacement] = React.useState('left')
return (
<>
setLabelPlacement(value as FormProps['labelPlacement'])}
/>
>
)
}
```
### 横向表单
适用于筛选或查询数据的场景,和表格配合使用
```tsx
import React from 'react'
import Form from '@hi-ui/form'
import Input from '@hi-ui/input'
import Button from '@hi-ui/button'
export const Placement = () => {
const FormItem = Form.Item
return (
<>
>
)
}
```
### 表单校验
可在Form中配置全部Item的rules,也可在Form.Item中使用rules校验单个表单项
```tsx
import React from 'react'
import Form, { FormHelpers, FormRules } from '@hi-ui/form'
import {
Input,
NumberInput,
Select,
Cascader,
Radio,
Button,
DatePicker,
TimePicker,
} from '@hi-ui/hiui'
export const Validate = () => {
const FormItem = Form.Item
const RadioGroup = Radio.Group
const formRef = React.useRef(null)
const [cascaderOptions] = React.useState([
{
id: '手机',
title: '手机',
children: [
{
id: '小米',
title: '小米',
children: [
{
id: '小米3',
title: '小米3',
},
{
id: '小米4',
title: '小米4',
},
],
},
],
},
])
const [rules] = React.useState({
region: [
{
required: true,
message: '请选择区域',
},
],
store: [
{
required: true,
message: '请选择门店',
},
],
count: [
{
validator: (rule, value, cb) => {
const count = +value
if (isNaN(count)) {
cb(new Error('请输入数字'))
} else if (count <= 0) {
cb(new Error('必须是正数'))
} else {
cb()
}
},
},
],
count2: [
{
required: true,
message: '请输入数量',
},
],
})
return (
<>
>
)
}
```
### 校验指定表单项
针对单个表单控件值进行校验
```tsx
import React from 'react'
import Form, { FormHelpers } from '@hi-ui/form'
import Input from '@hi-ui/input'
import Button from '@hi-ui/button'
import Grid from '@hi-ui/grid'
export const ValidateField = () => {
const { Row, Col } = Grid
const FormItem = Form.Item
const FormReset = Form.Reset
const FormSubmit = Form.Submit
const formRef = React.useRef(null)
const [formData, setFormData] = React.useState({
phone: '',
passwordConfirm: '',
password: '',
code: '',
})
const [countDown, setCountDown] = React.useState(60)
const [codeDisabled, setCodeDisabled] = React.useState(false)
const getCode = () => {
const countDownTimer = setInterval(() => {
if (countDown - 1 <= 0) {
clearInterval(countDownTimer)
setCountDown(60)
setCodeDisabled(false)
return
}
setCountDown((prev) => prev - 1)
}, 1000)
}
return (
<>
>
)
}
```
### 是否显示校验提示
适用于无需展示校验提示的场景
```tsx
import React from 'react'
import Form from '@hi-ui/form'
import Input from '@hi-ui/input'
import Button from '@hi-ui/button'
import Card from '@hi-ui/card'
export const ValidateMessage = () => {
const FormItem = Form.Item
return (
<>
>
)
}
```
### 滑动到错误字段
校验失败时,表单会自动滚动至第一个未通过的表单项
```tsx
import React from 'react'
import Form, { FormHelpers, FormRules } from '@hi-ui/form'
import Input from '@hi-ui/input'
import { Select } from '@hi-ui/select'
import { Cascader } from '@hi-ui/cascader'
import Radio from '@hi-ui/radio'
import Button from '@hi-ui/button'
export const ScrollToError = () => {
const FormItem = Form.Item
const RadioGroup = Radio.Group
const formRef = React.useRef(null)
const [cascaderOptions] = React.useState([
{
id: '手机',
title: '手机',
children: [
{
id: '小米',
title: '小米',
children: [
{
id: '小米3',
title: '小米3',
},
{
id: '小米4',
title: '小米4',
},
],
},
],
},
])
const [rules] = React.useState({
region: [
{
required: true,
message: '请选择区域',
},
],
store: [
{
required: true,
message: '请选择门店',
},
],
count: [
{
required: true,
validator: (rule, value, cb) => {
const count = +value
if (isNaN(count)) {
cb(new Error('请输入数字'))
} else if (count <= 0) {
cb(new Error('必须是正数'))
} else {
cb()
}
},
},
],
})
return (
<>
>
)
}
```
### 设置表单值
控制表单项的值
```tsx
import React from 'react'
import Form, { FormHelpers } from '@hi-ui/form'
import Input from '@hi-ui/input'
import Button from '@hi-ui/button'
import { Select } from '@hi-ui/select'
import Grid from '@hi-ui/grid'
export const SetValues = () => {
const { Row, Col } = Grid
const FormItem = Form.Item
const FormSubmit = Form.Submit
const FormReset = Form.Reset
const formRef = React.useRef(null)
const [singleList] = React.useState([
{ title: '电视', id: '3', disabled: true },
{ title: '手机', id: '2' },
])
return (
<>
>
)
}
```
### 获取表单值
静默获取表单值:不触发校验
```tsx
import React from 'react'
import Form, { FormHelpers } from '@hi-ui/form'
import Input from '@hi-ui/input'
import Button from '@hi-ui/button'
import message from '@hi-ui/message'
export const GetValues = () => {
const FormItem = Form.Item
const formRef = React.useRef(null)
return (
<>
>
)
}
```
### 自定义渲染表单控件
```tsx
import React from 'react'
import Form from '@hi-ui/form'
import Input from '@hi-ui/input'
export const Render = () => {
const FormItem = Form.Item
return (
<>
>
)
}
```
### 字段嵌套
```tsx
import React from 'react'
import Form, { FormHelpers } from '@hi-ui/form'
import Input from '@hi-ui/input'
export const NestedField = () => {
const FormItem = Form.Item
const FormReset = Form.Reset
const FormSubmit = Form.Submit
const formRef = React.useRef(null)
return (
<>
>
)
}
```
### 动态表单组
动态 Form 删减表单组
```tsx
import React from 'react'
import Form, { FormListHelper } from '@hi-ui/form'
import Input from '@hi-ui/input'
import Button from '@hi-ui/button'
export const List = () => {
const FormItem = Form.Item
const FormList = Form.List
const formListRef = React.useRef(null)
return (
<>
>
)
}
```
### 表单联动
根据数据控制某个表单的显示隐藏或校验规则
```tsx
import React from 'react'
import Form, { FormHelpers } from '@hi-ui/form'
import Button from '@hi-ui/button'
import message from '@hi-ui/message'
import Select from '@hi-ui/select'
import { Counter } from '@hi-ui/counter'
import Checkbox from '@hi-ui/checkbox'
import { DatePicker } from '@hi-ui/date-picker'
import { Cascader } from '@hi-ui/cascader'
import Radio from '@hi-ui/radio'
import { Switch } from '@hi-ui/switch'
import { Rating } from '@hi-ui/rating'
import { Upload } from '@hi-ui/upload'
export const Cascade = () => {
const FormItem = Form.Item
const FormReset = Form.Reset
const FormSubmit = Form.Submit
const CheckboxGroup = Checkbox.Group
const RadioGroup = Radio.Group
const formRef = React.useRef(null)
const [formData, setFormData] = React.useState({
controlCounter: 'show',
select: '3',
counter: 3,
radio: 0,
rating: 3,
checkbox: [],
switch: false,
})
return (
<>
>
)
}
```
### 自定义样式
Form 传入的 label/content 会作为所有 Form.Item 的默认样式;Form.Item 单独传入 label/content 时以 Form.Item 为准(覆盖 Form)
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Form, { FormSemanticName } from '@hi-ui/form'
import Input from '@hi-ui/input'
export const Semantic = () => {
const [selected, setSelected] = useState()
const FormItem = Form.Item
const highlightOutline = { outline: '2px solid #ffbe0a' }
return (
<>
{
return (
{
setSelected(dataItem.title as FormSemanticName)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Form Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------- | ---------- |
| innerRef | 提供辅助方法的内部引用 | Ref\>> | - | - |
| labelWidth | label 宽度,可用任意 CSS 长度单位 | ReactText | - | - |
| labelPlacement | label 对齐的方式 | "left" \| "right" \| "top" | "left" \| "right" \| "top" | "right" |
| placement | label 和表单控件的放置方式 | "vertical" \| "horizontal" | "vertical" \| "horizontal" | "vertical" |
| contentPosition | 在 vertical 放置时,label 相对表单控件垂直对齐的方式 | "top" \| "center" \| "bottom" | "top" \| "center" \| "bottom" | "center" |
| showColon | 配置是否展示冒号 | boolean | true \| false | - |
| showRequiredOnValidateRequired | FormItem 开启 filed 的 required 校验时,展示红色星号 | boolean | true \| false | false |
| showValidateMessage | 是否显示校验提示 | boolean | true \| false | true |
| size | 设置表单尺寸 | HiBaseSizeEnum | "xs" \| "sm" \| "md" \| "lg" | - |
| initialValues *(required)* | 初始化表单值,只在初始化以及重置时生效;该值是不受控的,和表单中的 defaultValue 的作用类似 | Record\ | - | - |
| initialErrors | 初始化表单错误 | Record\ | - | - |
| rules | 校验规则,设置字段的校验逻辑 | Record\ | - | - |
| validateTrigger | 设置统一的表单校验时机 | string \| string\[] | string \| string\[] | - |
| onValuesChange | 字段值更新时触发回调事件:changedValues: 改变的表单对象,allValues: 所有表单项对象 | ((changedValue: Record\, allValues: Record\) => void) | - | - |
| onSubmit | 提交时回调 | ((values: Record\) => void) | - | - |
| onReset | 重置时回调 | ((values: Record\) => void \| Promise\) | (values: Record\) => void \| Promise\ | - |
| scrollToFirstError | 提交失败自动滚动到第一个错误字段,配置参考:https\://github.com/scroll-into-view/scroll-into-view-if-needed?tab=readme-ov-file#options | boolean \| StandardBehaviorOptions | false \| true \| StandardBehaviorOptions | - |
| classNames | | FormSemanticClassNames | - | - |
| styles | | FormSemanticStyles | - | - |
### FormItem Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| children | 表单控件或其渲染函数 | ((string \| number \| boolean \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| ((props: Record<...>) => ReactNode)) & (boolean \| ... 2 more ... \| ReactPortal)) \| null | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| string & {} \| (props: Record\) => ReactNode \| string & ReactElement\> \| string & ReactNodeArray \| string & ReactPortal \| number & {} \| number & ReactElement\> \| number & ReactNodeArray \| number & ReactPortal \| false & {} \| false & ReactElement\> \| false & ReactNodeArray \| false & ReactPortal \| true & {} \| true & ReactElement\> \| true & ReactNodeArray \| true & ReactPortal \| {} & string \| {} & number \| {} & false \| {} & true \| ReactElement\> & string \| ReactElement\> & number \| ReactElement\> & false \| ReactElement\> & true \| ReactElement\> & ReactNodeArray \| ReactElement\> & ReactPortal \| ReactNodeArray & string \| ReactNodeArray & number \| ReactNodeArray & false \| ReactNodeArray & true \| ReactNodeArray & ReactElement\> \| ReactNodeArray & ReactPortal \| ReactPortal & string \| ReactPortal & number \| ReactPortal & false \| ReactPortal & true \| ReactPortal & ReactElement\> \| ReactPortal & ReactNodeArray \| ((props: Record\) => ReactNode) & string \| ((props: Record\) => ReactNode) & number \| ((props: Record\) => ReactNode) & false \| ((props: Record\) => ReactNode) & true \| ((props: Record\) => ReactNode) & ReactElement\> \| ((props: Record\) => ReactNode) & ReactNodeArray \| ((props: Record\) => ReactNode) & ReactPortal | - |
| render | 支持表单控件 render 渲染 | ((props: Record\) => any) | - | - |
| field | 字段名,支持数组 | FormFieldPath | - | - |
| valueType | 指定控件值数据结构类型 | FormRuleType | - | - |
| rules | 设置字段的验证规则,会覆盖 Form 设置的 rules | FormRuleModel\[] | - | - |
| valuePropName | 自定义设置 Form 往表单控件注入值的属性,如 Switch Radio Checkbox 的是 'checked' | string | - | - |
| valueDispatchTransform | form 从控件个体采集数据的转换器,最终会把返回值转发给 Form | ((...args: any\[]) => any) | - | - |
| valueConnectTransform | 控件个体接收 form 下发数据的转换器,最终会把返回值转发给 FormField | ((value: any) => any) | - | - |
| valueChangeFuncPropName | 自定义设置 Form 从表单控件采集数据回调的属性 | string | - | - |
| validateTrigger | 设置触发该字段校验的时机(值必须是回调函数),会覆盖 Form 设置的 validateTrigger | string \| string\[] | string \| string\[] | - |
| itemClassNames | 由 Form.Item 传入的语义化 classNames(label / content),勿直接使用
@internal | FormLabelSemanticClassNames | - | - |
| itemStyles | 由 Form.Item 传入的语义化 styles(label / content),勿直接使用
@internal | FormLabelSemanticStyles | - | - |
| labelPlacement | label 放置的位置 | "left" \| "right" \| "top" | "left" \| "right" \| "top" | - |
| required | 是否显示必填信号。这里不做校验处理,若需校验请使用 rules 进行设置 | boolean | true \| false | - |
| showColon | 是否显示冒号 | boolean | true \| false | - |
| labelWidth | label 宽度,可使用任意 CSS 长度单位。优先级高于 Form 设置的 labelWidth | ReactText | - | - |
| label | label 文案 | ReactNode | - | - |
| contentPosition | 在 vertical 放置时,label 相对表单控件垂直对齐的方式,优先级低于 Form | "top" \| "center" \| "bottom" | "top" \| "center" \| "bottom" | - |
| formMessage | 提示信息 | ReactNode | - | - |
| showValidateMessage | 是否显示校验提示。优先级高于 Form 设置的 showValidateMessage | boolean | true \| false | - |
| classNames | | FormItemSemanticClassNames | - | - |
| styles | | FormItemSemanticStyles | - | - |
### FormList Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ------ |
| children | 表单控件渲染函数 | ((fields: FormListChildField\[], action: FormListChildrenAction) => ReactElement\>) | (fields: FormListChildField\[], action: FormListChildrenAction) => ReactElement\> | - |
| name *(required)* | 列表名称 | FormFieldPath | - | - |
| innerRef | 提供辅助方法的内部引用 | Ref\ | - | - |
### FormSubmit Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | --------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| onClick | 点击提交后触发 | ((result: any, error: any) => void) | - | - |
| type | 设置按钮类型 | "primary" \| "success" \| "danger" \| "default" \| "secondary" | "primary" \| "success" \| "danger" \| "default" \| "secondary" | "primary" |
| size | 设置按钮尺寸 | "xs" \| "sm" \| "md" \| "lg" | "xs" \| "sm" \| "md" \| "lg" | - |
| target | 同 a 标签的 target 属性,仅在设置 href 后有效 | "\_self" \| "\_blank" \| "\_parent" \| "\_top" | "\_self" \| "\_blank" \| "\_parent" \| "\_top" | - |
| classNames | | ButtonSemanticClassNames | - | - |
| styles | | ButtonSemanticStyles | - | - |
| href | 设置按钮链接,设置后将用 a 标签渲染按钮 | string | - | - |
| disabled | 设置按钮是否禁用 | boolean | true \| false | - |
| appearance | 设置按钮外观 | "link" \| "line" \| "text" \| "solid" \| "filled" | "link" \| "line" \| "text" \| "solid" \| "filled" | - |
| loading | 是否显示 loading | boolean | true \| false | - |
| icon | 设置按钮图标 | ReactNode \| ReactNode\[] | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| ReactNode\[] | - |
| shape | 设置按钮形状 | "square" \| "round" | "square" \| "round" | - |
### FormReset Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | --------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| onClick | 点击重置后触发 | (() => void) | - | - |
| type | 设置按钮类型 | "primary" \| "success" \| "danger" \| "default" \| "secondary" | "primary" \| "success" \| "danger" \| "default" \| "secondary" | - |
| size | 设置按钮尺寸 | "xs" \| "sm" \| "md" \| "lg" | "xs" \| "sm" \| "md" \| "lg" | - |
| appearance | 设置按钮外观 | "link" \| "line" \| "text" \| "solid" \| "filled" | "link" \| "line" \| "text" \| "solid" \| "filled" | - |
| disabled | 设置按钮是否禁用 | boolean | true \| false | - |
| loading | 是否显示 loading | boolean | true \| false | - |
| href | 设置按钮链接,设置后将用 a 标签渲染按钮 | string | - | - |
| target | 同 a 标签的 target 属性,仅在设置 href 后有效 | "\_self" \| "\_blank" \| "\_parent" \| "\_top" | "\_self" \| "\_blank" \| "\_parent" \| "\_top" | - |
| icon | 设置按钮图标 | ReactNode \| ReactNode\[] | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| ReactNode\[] | - |
| shape | 设置按钮形状 | "square" \| "round" | "square" \| "round" | - |
| classNames | | ButtonSemanticClassNames | - | - |
| styles | | ButtonSemanticStyles | - | - |
### FormLabel Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------- | --------------------------------------------------------------------------------- | ----------------------------- | ----------------------------- | ------ |
| itemClassNames | 由 Form.Item 传入的语义化 classNames(label / content),勿直接使用
@internal | FormLabelSemanticClassNames | - | - |
| itemStyles | 由 Form.Item 传入的语义化 styles(label / content),勿直接使用
@internal | FormLabelSemanticStyles | - | - |
| labelPlacement | label 放置的位置 | "left" \| "right" \| "top" | "left" \| "right" \| "top" | - |
| required | 是否显示必填信号。这里不做校验处理,若需校验请使用 rules 进行设置 | boolean | true \| false | - |
| showColon | 是否显示冒号 | boolean | true \| false | - |
| labelWidth | label 宽度,可使用任意 CSS 长度单位。优先级高于 Form 设置的 labelWidth | ReactText | - | - |
| label | label 文案 | ReactNode | - | - |
| contentPosition | 在 vertical 放置时,label 相对表单控件垂直对齐的方式,优先级低于 Form | "top" \| "center" \| "bottom" | "top" \| "center" \| "bottom" | - |
| formMessage | 提示信息 | ReactNode | - | - |
| showValidateMessage | 是否显示校验提示。优先级高于 Form 设置的 showValidateMessage | boolean | true \| false | - |
## Type
### FormFieldPath
> (string | number)[] | string | number
### FormHelpers
| 名称 | 说明 | 类型 |
| ------------------ | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| reset | 重置整个表单的验证,对应 Form.Reset 中的 API,如果不指定 nextState,则重置为 initialValues | (nextState?: { values?: any, errors?: any }) => Promise |
| validate | 对整个表单进行校验, 对应 Form.Submit 中的 API | () => Promise> |
| validateField | 对指定表单字段进行校验 | (fields: FormFieldPath) => Promise |
| setFieldValue | 设置某个表单字段的值,在更新表单数据的的时候,使用该方法 | (field: FormFieldPath, value: any) => void |
| setFieldsValue | 设置多个表单的值,在异步获取的数据回显的时候,使用该方法 | (field: Record \| ((prevValues: Record) => Record)) => void |
| getFieldValue | 获取一个字段名对应的 Value,返回为对应 Field 值 | (field: FormFieldPath) => any |
| getFieldsValue | 获取所有字段名对应的 Values 返回为字典映射数据结构 | () => Record |
| getFieldError | 获取一组字段名对应的 errorMessage,返回为对应 field 错误信息 | (field: FormFieldPath) => any |
| getFieldsError | 获取所有字段名对应的错误信息,返回为字典映射数据结构 | () => Record |
| clearValidates | 移除所有表单项的校验结果 | () => void |
| clearFieldValidate | 移除表单项的校验结果,传入待移除的表单项的 field 属性组成的数组 | (fields: FormFieldPath) => void |
### FormRuleModel
> [更多规则](https://github.com/yiminghe/async-validator)
| 名称 | 说明 | 类型 |
| -------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| enum | 是否匹配枚举中的值 | any[] |
| len | string 类型时为字符串长度;number 类型时为确定数字; array 类型时为数组长度 | number |
| max | 必须设置 `type`:string 类型为字符串最大长度;number 类型时为最大值;array 类型时为数组最大长度 | number |
| message | 错误信息 | string |
| min | 必须设置 `type`:string 类型为字符串最小长度;number 类型时为最小值;array 类型时为数组最小长度 | number |
| pattern | 正则表达式匹配 | RegExp |
| required | 是否为必选字段 | boolean |
| transform | 将字段值转换成目标值后进行校验 | (value) => any |
| type | 类型,常见有 `string` \|`number` \|`boolean` \| `email`。更多请参考[此处](https://github.com/yiminghe/async-validator#type) | string |
| validator | 自定义校验 | (rule,value,callback) => void |
| asyncValidator | 自定义异步校验 | (rule,value,callback) => void | Promise |
| whitespace | 如果字段仅包含空格则校验不通过 | boolean |
# GlobalContext 上下文
全局设置上下文。
## 使用示例
### 基础用法
```tsx
import React, { useContext } from 'react'
import { GlobalContext } from '@hi-ui/global-context'
export const Basic = () => {
useContext(GlobalContext)
return (
<>
>
)
}
```
## Props
### GlobalProvider Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------ | ---- | ---------------- | ------ | ------ |
| value *(required)* | | UseGlobalContext | - | - |
# Grid 栅格组件
24 栏栅格系统,用于实现内容区域的各种布局
## 使用示例
### 基础用法
无间隔水平排列
```tsx
import React from 'react'
import Grid from '@hi-ui/grid'
export const Basic = () => {
const { Row, Col } = Grid
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
return (
<>
col-24
col-6
25%
col-6
25%
col-6
25%
col-6
25%
col-6
25%
col-6
25%
>
)
}
```
### 区块间隔
在 Row 设置 gutter = true 来使水平排列有间隔
```tsx
import React from 'react'
import Grid from '@hi-ui/grid'
export const Gutter = () => {
const { Row, Col } = Grid
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
return (
<>
col-6
25%
col-6
25%
col-6
25%
col-6
25%
>
)
}
```
### 左右偏移
设置 offset 来指定左右的偏移量
```tsx
import React from 'react'
import Grid from '@hi-ui/grid'
export const Offset = () => {
const { Row, Col } = Grid
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
return (
<>
col-8
col-6-offset-6
col-4
col-4
col-6-offset-4
col-4
col-6
>
)
}
```
### 嵌套
嵌套栅格来完成布局
```tsx
import React from 'react'
import Grid from '@hi-ui/grid'
export const Nested = () => {
const { Row, Col } = Grid
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
return (
<>
>
)
}
```
### 对齐排列
设置 justify 来指定对齐方式
```tsx
import React from 'react'
import Grid from '@hi-ui/grid'
export const Justify = () => {
const { Row, Col } = Grid
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
return (
<>
col-6
col-6
col-6
col-6
col-6
>
)
}
```
### 响应式
配置 span 在不同屏幕宽度下所包含的栅格数,支持 { xs, sm, md, lg, xl } 设置。请通过改变窗口宽度查看示例效果
```tsx
import React from 'react'
import Grid from '@hi-ui/grid'
export const Responsive = () => {
const { Row, Col } = Grid
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
return (
<>
span
.xs-24 .md-12 .lg-6
.xs-24 .md-12 .lg-6
.xs-24 .md-12 .lg-6
.xs-24 .md-12 .lg-6
offset
.xs-12 .md-8
xs-12 .md-8
xs-12 .md-8
>
)
}
```
### 重排序
通过配置 order 优化 Grid 项的展示空间的排序位置
```tsx
import React from 'react'
import Grid from '@hi-ui/grid'
export const Order = () => {
const { Row, Col } = Grid
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
return (
<>
>
)
}
```
### AutoGrid 基础
children / columnCount / data-span / gutter 用法
```tsx
import React from 'react'
import { AutoGrid } from '@hi-ui/grid'
export const AutoGridBasic = () => {
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
return (
<>
children 默认 3 列
{[1, 2, 3, 4, 5, 6].map((i) => (
Item {i}
))}
子元素可通过 span / data-span 自定义占据栅格数
span 12
span 12
span 8
span 8
span 8
>
)
}
```
### AutoGrid Nodes API
使用 nodes 替代 children,支持 props 对象或函数
```tsx
import React from 'react'
import { AutoGrid } from '@hi-ui/grid'
export const AutoGridNodes = () => {
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
const nodes = [
{ key: '1', elem: 1
},
{
key: '2',
elem: 2
,
props: { span: 16 },
},
{
key: '3',
elem: 3
,
props: ({ columnCount }: { columns: number; columnCount: number }) => ({
span: 24,
}),
},
]
return (
<>
>
)
}
```
### DynamicGrid 基础
可拖拽容器调整宽度,根据 breakpoints 自动调整列数,onColumnCountChange 回调当前列数
```tsx
import React, { useState } from 'react'
import { DynamicGrid } from '@hi-ui/grid'
export const DynamicGridBasic = () => {
const [count, setCount] = useState(0)
const blockStyle: React.CSSProperties = {
width: '100%',
padding: '16px 0',
textAlign: 'center',
opacity: '1',
color: '#fff',
}
const resizeStyle: React.CSSProperties = {
resize: 'horizontal',
overflow: 'auto',
width: 500,
minWidth: 300,
maxWidth: 860,
border: '2px dashed #e5e7eb',
borderRadius: 8,
padding: 16,
}
const breakpoints: [number, number][] = [
[400, 1],
[600, 2],
[Infinity, 3],
]
console.log('count', count)
return (
<>
{
console.log('onColumnCountChange', count)
setCount(count)
}}
gutter
rowGap={16}
>
{[1, 2, 3, 4, 5, 6].map((i) => (
Item {i}
))}
可拖拽容器右侧边缘调整宽度,观察列数自动变化,当前列数: {count || '-'}
>
)
}
```
## Props
### Row Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------- | ------------------------------------------ | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------ |
| align | 垂直对齐方式 | GridAlignEnum \| GridResponsiveSize\ | "flex-start" \| "flex-end" \| "center" \| "stretch" \| GridResponsiveSize\ | - |
| justify | 水平对齐方式 | GridJustifyEnum \| GridResponsiveSize\ | "flex-start" \| "flex-end" \| "center" \| "space-around" \| "space-between" \| GridResponsiveSize\ | - |
| gutter | Row 里面元素之间是否有外边距,建议使用偶数 | number \| boolean | number \| false \| true | - |
| columns | 设置栅格列总数,一般是 12 或者 24 或者 48 | number | - | 24 |
| rowGap | Row 与 Row 之间的距离 | number | - | 16 |
### Col Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------- | ----------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------ |
| span | Col 元素占多少个栅格 | number \| GridResponsiveSize\ | number \| GridResponsiveSize\ | - |
| offset | Col 元素偏移多少个栅格 | number \| GridResponsiveSize\ | number \| GridResponsiveSize\ | - |
| justify | 里面的元素排布方式 | GridJustifyEnum \| GridResponsiveSize\ | "flex-start" \| "flex-end" \| "center" \| "space-around" \| "space-between" \| GridResponsiveSize\ | - |
| order | Col项重排序,数值越大,越在后面展示 | number \| GridResponsiveSize\ | number \| GridResponsiveSize\ | - |
### AutoGrid Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| align | 垂直对齐方式 | GridAlignEnum \| GridResponsiveSize\ | "flex-start" \| "flex-end" \| "center" \| "stretch" \| GridResponsiveSize\ | - |
| justify | 水平对齐方式 | GridJustifyEnum \| GridResponsiveSize\ | "flex-start" \| "flex-end" \| "center" \| "space-around" \| "space-between" \| GridResponsiveSize\ | - |
| gutter | Row 里面元素之间是否有外边距,建议使用偶数 | number \| boolean | number \| false \| true | true |
| columns | 设置栅格列总数,一般是 12 或者 24 或者 48 | number | - | 24 |
| rowGap | Row 与 Row 之间的距离 | number | - | 0 |
| children | 子元素清单
- 存在子元素时,会自动按照默认的配置增加网格包裹
- 如需控制子元素占据的网格数,请在元素上增加 span 或者 data-span 属性 | ((boolean \| ReactChild \| ReactFragment \| ReactPortal \| null) & ReactNode\[]) | ReactNode\[] \| string & ReactNode\[] \| number & ReactNode\[] \| false & ReactNode\[] \| true & ReactNode\[] \| ReactElement\> & ReactNode\[] \| ReactNodeArray & ReactNode\[] \| ReactPortal & ReactNode\[] | - |
| nodes | 列元素清单 | AutoGridNodeType\[] | - | - |
| columnCount | 列数 | number | - | - |
### DynamicGrid Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| align | 垂直对齐方式 | GridAlignEnum \| GridResponsiveSize\ | "flex-start" \| "flex-end" \| "center" \| "stretch" \| GridResponsiveSize\ | - |
| justify | 水平对齐方式 | GridJustifyEnum \| GridResponsiveSize\ | "flex-start" \| "flex-end" \| "center" \| "space-around" \| "space-between" \| GridResponsiveSize\ | - |
| gutter | Row 里面元素之间是否有外边距,建议使用偶数 | number \| boolean | number \| false \| true | - |
| columns | 设置栅格列总数,一般是 12 或者 24 或者 48 | number | - | - |
| rowGap | Row 与 Row 之间的距离 | number | - | - |
| children | 子元素清单
- 存在子元素时,会自动按照默认的配置增加网格包裹
- 如需控制子元素占据的网格数,请在元素上增加 span 或者 data-span 属性 | ((boolean \| ReactChild \| ReactFragment \| ReactPortal \| null) & ReactNode\[]) | ReactNode\[] \| string & ReactNode\[] \| number & ReactNode\[] \| false & ReactNode\[] \| true & ReactNode\[] \| ReactElement\> & ReactNode\[] \| ReactNodeArray & ReactNode\[] \| ReactPortal & ReactNode\[] | - |
| nodes | 列元素清单 | AutoGridNodeType\[] | - | - |
| columnCount | 列数
列数,表示一行包含元素的数量
@desc 传入此值时,列数固定,不因容器宽度变化而变化
@desc 不传时,但额外传入 wrapperElRef 时,列数会根据容器宽度变化而变化 | number | - | "3" |
| defaultColumnCount | 默认列数
@desc 与 columnCount 的区别是,仅会在初始化时使用
@desc 传入后,列数仍会根据容器宽度变化而变化 | number | - | - |
| wrapperElRef | 组件的外部包裹元素
@desc 传入此值,同时不传 columnCount 时,列数会根据容器宽度变化而变化 | RefObject\ | - | - |
| onColumnCountChange | 实际可视列数变化回调 | ((columnCount: number) => void) | - | - |
| breakpoints | 列数变化断点
@desc 默认使用 GRID\_VIEWPORT\_BREAKPOINTS: \[576, 1], \[768, 2], \[992, 3], \[1200, 4], \[Infinity, 4] | BreakpointType\[] | - | - |
| sensitive | 是否对初始布局变化敏感
@desc 当设置为 true 时,会等待布局稳定后再渲染内容,避免视觉跳动 | boolean | true \| false | - |
## Type
### GridResponsiveSize
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ---------------- | --------- | ------------- | ------ |
| xs | 设置屏幕 < 576px 时响应式栅格数 | T | - | - |
| sm | 设置屏幕 >= 576px 时响应式栅格数 | T | - | - |
| md | 设置屏幕 >= 768px 时响应式栅格数 | T | - | - |
| lg | 设置屏幕 >= 992px 时响应式栅格数 | T | - | - |
| xl | 设置屏幕 >= 1200px 时响应式栅格数 | T | - | - |
# Highlighter 文本高亮
用于文本关键字高亮展示,实现快速结果匹配。
## 使用示例
### 基础用法
```tsx
import React from 'react'
import Highlighter from '@hi-ui/highlighter'
export const Basic = () => {
return (
<>
我想要高亮的文案是:高亮
>
)
}
```
### 自定义匹配规则
```tsx
import React from 'react'
import Highlighter from '@hi-ui/highlighter'
export const Rule = () => {
return (
<>
关键字 hiui,可以匹配上 hiui,也可匹配上 HiUI
>
)
}
```
### 设置高亮样式
```tsx
import React from 'react'
import Highlighter from '@hi-ui/highlighter'
export const Style = () => {
return (
<>
请注意,这是一段高危操作!!
>
)
}
```
## Props
### Highlighter Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------ | -------------- | ---------------- | ---------------- | ------ |
| keyword | 匹配高亮关键词 | string \| RegExp | string \| RegExp | - |
| highlightClassName | 高亮类名 | string | - | - |
| highlightStyle | 高亮样式 | CSSProperties | - | - |
# IconButton 图标按钮
带有图标的按钮。
## 使用示例
### 基础用法
```tsx
import React from 'react'
import IconButton from '@hi-ui/icon-button'
import { CloseOutlined } from '@hi-ui/icons'
export const Basic = () => {
return (
<>
} />
} active />
} effect />
} effect active />
测试
} effect />
文档流空间是否占用
>
)
}
```
## Props
### IconButton Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | ----------------------------------------- | --------- | ------------- | ------ |
| icon *(required)* | icon 图标 | ReactNode | - | - |
| active | 是否被激活 | boolean | true \| false | false |
| virtualArea | 扩大点击区域 | boolean | true \| false | true |
| effect | 是否开启 hover 和 focus 展示底色变化效果 | boolean | true \| false | false |
| disabled | 是否禁用 | boolean | true \| false | false |
| effectColor | 鼠标悬浮时的颜色 | string | - | - |
# Input 输入框
用来接收文本型内容的组件
## 使用示例
### 基础用法
可获取有限长度的字符串,不折行显示
```tsx
import React from 'react'
import Input from '@hi-ui/input'
export const Basic = () => {
return (
<>
console.log(e.target.value, t)} />
>
)
}
```
### 受控
```tsx
import React from 'react'
import Input from '@hi-ui/input'
export const Controlled = () => {
const [value, setValue] = React.useState('我是输入文本')
return (
<>
>
)
}
```
### 不同UI风格
UI风格包括线性、面性、无UI三种
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import { ExpressionOutlined, AudioOutlined, MessageOutlined } from '@hi-ui/icons'
export const Appearance = () => {
return (
<>
>
)
}
```
### 不同尺寸
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import { ExpressionOutlined, AudioOutlined } from '@hi-ui/icons'
export const Size = () => {
return (
<>
>
)
}
```
### 前后外置元素
将输入框与外置的其他元素组合使用
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import { ExpressionOutlined, AudioOutlined, SearchOutlined, MessageOutlined } from '@hi-ui/icons'
export const Addon = () => {
return (
<>
mixin addon
}
suffix={
}
append={
Send
}
>
>
)
}
```
### 组合
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import { SearchOutlined } from '@hi-ui/icons'
import { Select } from '@hi-ui/select'
import { message } from '@hi-ui/message'
import Button from '@hi-ui/button'
export const Group = () => {
return (
<>
}
/>
}
onClick={() => {
message.open({ type: 'success', title: '查询成功', duration: 2000 })
}}
/>
}
/>
>
)
}
```
### 可清除
```tsx
import React from 'react'
import Input from '@hi-ui/input'
export const Clearable = () => {
return (
<>
console.log('change', e.target.value)}
onBlur={(e) => console.log('onBlur', e.target.value)}
>
>
)
}
```
### 无效状态
```tsx
import React from 'react'
import Input from '@hi-ui/input'
export const Invalid = () => {
return (
<>
>
)
}
```
### 禁用状态
```tsx
import React from 'react'
import Input from '@hi-ui/input'
export const Disabled = () => {
return (
<>
>
)
}
```
### 手动聚焦
通过 ref 获取 input 引用手动调用 focus 方法
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import Button from '@hi-ui/button'
export const Focus = () => {
const inputRef = React.useRef(null)
return (
<>
>
)
}
```
### 自动 Trim
```tsx
import React from 'react'
import Input from '@hi-ui/input'
export const Trim = () => {
return (
<>
console.log('change', e.target.value)}
trimValueOnBlur
>
>
)
}
```
### 特殊格式
满足不同业务场景的特殊格式
```tsx
import React from 'react'
import Input from '@hi-ui/input'
export const Type = () => {
return (
<>
身份证
{
console.log(event.target.value, value)
}}
/>
手机号
{
console.log(event.target.value, value)
}}
/>
金额
{
console.log(event.target.value, value)
}}
/>
银行卡
{
console.log(event.target.value, value)
}}
/>
>
)
}
```
### 带Tooltip
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import Tooltip from '@hi-ui/tooltip'
export const WithTooltip = () => {
const [value, setValue] = React.useState('Tooltip')
return (
<>
setValue(e.target.value)}
>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Input, { InputSemanticName } from '@hi-ui/input'
export const Semantic = () => {
const [selected, setSelected] = useState()
return (
<>
>
)
}
```
## Props
### Input Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------ | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------- |
| readOnly | 开启输入框只读 | boolean | true \| false | - |
| disabled | 是否禁用 | boolean | true \| false | - |
| autoFocus | 开启输入框自动聚焦 | boolean | true \| false | - |
| value | 设置输入框的值 | string | - | - |
| defaultValue | 设置输入框的默认值 | string | - | - |
| type | 设置输入框类型 | InputTypeEnum | "number" \| "text" \| "id" \| "tel" \| "card" \| "amount" \| "email" \| "password" | - |
| maxLength | 输入最大长度 | number | - | - |
| prepend | 输入框前置外部内容 | ReactNode | - | - |
| append | 输入框后置外部内容 | ReactNode | - | - |
| prefix | 输入框前置内容 | ReactNode | - | - |
| suffix | 输入框后置内容 | ReactNode | - | - |
| clearable | 是否可清空,通过点击右侧清除按钮 | boolean | true \| false | false |
| trimValueOnBlur | 开启失焦时触发对值的 trim,将触发 onChange 给用户 | boolean | true \| false | - |
| clearableTrigger | 清除按钮展示的触发形态 | "always" \| "hover" | "always" \| "hover" | "hover" |
| placeholder | 输入框占位符 | string | - | - |
| appearance | 设置展现形式
其中 \`underline\` 内部使用,不对外提供支持(风格去线型化:由线性过渡到面性) | InputAppearanceEnum | "line" \| "filled" \| "unset" \| "borderless" \| "underline" | "line" |
| size | 设置尺寸 | HiBaseSizeEnum | "xs" \| "sm" \| "md" \| "lg" | - |
| onChange | 值改变时的回调 | ((evt: ChangeEvent\, value: string) => void) | - | - |
| waitCompositionEnd | 是否等待文本段落组成完成 | boolean | true \| false | - |
| invalid | 开启表单控件组件输入无效态 | boolean | true \| false | false |
| classNames | | InputSemanticClassNames | - | - |
| styles | | InputSemanticStyles | - | - |
# InputGroup 输入框组合器
将表单控件或按钮进行组合,轻松扩展表单控件。
## 使用示例
### 基础用法
通过包裹多个表单控件,将它们进行组合展示
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import Select from '@hi-ui/select'
import InputGroup from '@hi-ui/input-group'
export const Basic = () => {
return (
<>
>
)
}
```
### 不同组合形式
根据不同场景组合不同类型的表单控件
```tsx
import React from 'react'
import Input from '@hi-ui/input'
import Select from '@hi-ui/select'
import CheckSelect from '@hi-ui/check-select'
import Cascader from '@hi-ui/cascader'
import DatePicker from '@hi-ui/date-picker'
import Button from '@hi-ui/button'
import InputGroup from '@hi-ui/input-group'
export const Group = () => {
return (
<>
{/* Input + button */}
>
)
}
```
## Props
### InputGroup Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | -------------------------------- | ------- | ------------- | ------ |
| disabled | 统一设置被包裹表单控件的禁用状态 | boolean | true \| false | - |
# Layout 布局组件
提供了布局框架
## 使用示例
### 基础布局
```tsx
import React from 'react'
import Layout, { Header, Sider, Content, Footer } from '@hi-ui/layout'
export const Basic = () => {
// 侧边栏导航是否折叠
const [collapsed, setCollapsed] = React.useState(false)
return (
<>
>
)
}
```
### 侧边栏带普通菜单
默认情况下,侧边栏是展开的,可拖拽收起
```tsx
import React from 'react'
import {
AppStoreFilled,
QuestionCircleFilled,
MonitorFilled,
MobileFilled,
PadFilled,
EllipsisOutlined,
PlusOutlined,
} from '@hi-ui/icons'
import {
Button,
Avatar,
PageHeader,
Space,
Dropdown,
Menu,
Scrollbar,
EllipsisTooltip,
} from '@hi-ui/hiui'
import Layout, { Sider, Content, SearchTrigger, ProfilePopover, ActionItem } from '@hi-ui/layout'
export const WithMenu = () => {
// 侧边栏导航是否折叠
const [collapsed, setCollapsed] = React.useState(true)
const [activeMenuId, setActiveMenuId] = React.useState(1)
const [profileVisible, setProfileVisible] = React.useState(false)
const [settingsValue, setSettingsValue] = React.useState({})
const data = [
{
title: '首页',
id: 1,
icon: ,
},
{
title: '电视',
id: 2,
icon: ,
},
{
title: '手机',
id: 3,
icon: ,
children: [
{
title: '小米',
id: 'xiaomi',
},
{
title: '红米',
id: 'redmi',
},
],
},
{
title: '平板',
id: 4,
icon: ,
},
]
return (
<>
{collapsed ? null : (
系统名称
)}
} mini={collapsed}>
使用手册
用户名
admin@example.com
}
footer={ setProfileVisible(false)}>退出登录
}
settings={{
value: settingsValue,
data: [
{
id: 'timezone',
title: '时区',
subtitle: 'UTC+08:00',
children: [
{ id: 'timezone-1', title: '时区1' },
{ id: 'timezone-2', title: '时区2' },
{ id: 'timezone-3', title: '时区3' },
],
},
{
id: 'language',
title: '语言',
subtitle: '中文',
children: [
{ id: 'language-1', title: '语言1' },
{ id: 'language-2', title: '语言2' },
{ id: 'language-3', title: '语言3' },
],
},
],
onItemClick: (evt, item) => {
// evt.preventDefault()
},
onChange: (value) => {
setSettingsValue(value)
setProfileVisible(false)
},
}}
onClose={() => setProfileVisible(false)}
>
setProfileVisible(!profileVisible)}
>
{collapsed ? null :
用户名}
} />
}>
主操作
}
/>
>
)
}
```
### 侧边栏带浮动菜单
菜单部分联动交互可根据需求自行实现,以下示例实现了一套默认联动交互
```tsx
import React from 'react'
import {
AppStoreFilled,
MonitorFilled,
MobileFilled,
PadFilled,
MenuOutlined,
EllipsisOutlined,
PlusOutlined,
QuestionCircleFilled,
} from '@hi-ui/icons'
import {
MenuDataItem,
GroupMenu,
SideMenu,
useSideMenuCascade,
Button,
IconButton,
Avatar,
PageHeader,
EllipsisTooltip,
Space,
Dropdown,
} from '@hi-ui/hiui'
import Layout, {
Sider,
Content,
SearchTrigger,
FloatMenuContainer,
AppListPopover,
ProfilePopover,
ActionItem,
} from '@hi-ui/layout'
export const FloatMenu = () => {
const [data] = React.useState([
{
title: '首页',
id: 1,
icon: ,
},
{
title: 'Hello World',
id: 2,
icon: ,
children: [
{
title: '小米电视',
id: 21,
children: [
{
title: '小米电视5',
id: 211,
},
{
title: '小米电视4',
id: 212,
},
{
title: '小米电视3',
id: 213,
},
{
title: '小米电视2',
id: 214,
},
{
title: '小米电视1',
id: 215,
},
],
},
],
},
{
title: 'Hello World Hello World',
id: 3,
icon: ,
children: [
{
title: '小米',
id: 'xiaomi',
children: [
{
title: '小米10',
id: 'xiaomi10',
},
{
title: '小米9',
id: 'xiaomi9',
},
{
title: '小米8',
id: 'xiaomi8',
},
{
title: '小米7',
id: 'xiaomi7',
},
{
title: '小米6',
id: 'xiaomi6',
},
{
title: '小米5',
id: 'xiaomi5',
},
{
title: '小米4',
id: 'xiaomi4',
},
{
title: '小米3',
id: 'xiaomi3',
},
{
title: '小米2',
id: 'xiaomi2',
},
{
title: '小米1',
id: 'xiaomi1',
},
],
},
{
title: '小米note',
id: 'xiaominote',
children: [
{
title: '小米 note5',
id: 'xiaomi note5',
},
{
title: '小米 note4',
id: 'xiaomi note4',
},
{
title: '小米 note3',
id: 'xiaomi note3',
},
{
title: '小米 note2',
id: 'xiaomi note2',
},
{
title: '小米 note1',
id: 'xiaomi note1',
},
],
},
],
},
{
title: '超长超长超长字符超长超长超长字符',
id: 4,
icon: ,
},
])
// 侧边栏导航是否折叠
const [collapsed, setCollapsed] = React.useState(true)
// 鼠标悬浮到侧边栏菜单项的 id
const [selectMenuId, setSelectMenuId] = React.useState('')
// 当前激活的菜单项的 id
const [activeMenuId, setActiveMenuId] = React.useState('xiaomi3')
// 定时器,用于优化浮动菜单的隐藏时体验
const timerRef = React.useRef | null>(null)
const timerRef2 = React.useRef | null>(null)
const sideMenuRef = React.useRef(null)
const floatContainerRef = React.useRef(null)
const siderRef = React.useRef(null)
const { submenuData, activeParentId } = useSideMenuCascade({
data,
selectId: selectMenuId,
activeId: activeMenuId,
})
console.log('submenuData', submenuData)
// 浮动菜单是否显示
const [floatContainerVisible, setFloatContainerVisible] = React.useState(false)
// 浮动菜单是否折叠
const [floatContainerCollapsed, setFloatContainerCollapsed] = React.useState(true)
// 应用列表是否显示
const [appListPopoverVisible, setAppListPopoverVisible] = React.useState(false)
// 激活的应用 id
const [activeAppId, setActiveAppId] = React.useState('')
const [profileVisible, setProfileVisible] = React.useState(false)
const [settingsValue, setSettingsValue] = React.useState({})
return (
<>
{collapsed ? null : (
系统名称
)}
,
iconBgColor: 'BLUE',
id: 1,
title: '应用1',
},
{
icon: 'Y',
iconBgColor: 'SKYBLUE',
id: 2,
title: '应用2',
},
{
icon: '',
iconBgColor: 'CYAN',
id: 3,
title: '应用3',
},
{
iconBgColor: 'GREEN',
id: 4,
title: '很长很长很长很长很长的应用名称',
},
{
iconBgColor: 'PURPLE',
id: 5,
title: '应用5',
},
{
iconBgColor: 'YELLOW',
id: 6,
title: '应用6',
},
{
iconBgColor: 'ORANGE',
id: 7,
title: '应用7',
},
{
iconBgColor: 'BLUE',
id: 8,
title: '应用8',
},
]}
titleRender={(item) => {
return
{item.title as string}
}}
onItemClick={(item) => {
setActiveAppId(item.id)
setAppListPopoverVisible(false)
}}
onOutsideClick={() => setAppListPopoverVisible(false)}
>
}
effectColor="rgba(124, 135, 166, 0.15)"
effect
onClick={() => {
setAppListPopoverVisible(!appListPopoverVisible)
}}
/>
{
// 阻止默认行为,设置后不会触发默认的搜索行为
// evt.preventDefault()
}}
/>
{
if (!item.children || item.children.length === 0) {
setActiveMenuId(id)
setFloatContainerVisible(false)
setFloatContainerCollapsed(true)
setSelectMenuId(id)
} else {
const submenuFirstItem = submenuData[0]?.children?.[0]
if (submenuFirstItem) {
setActiveMenuId(submenuFirstItem.id)
setFloatContainerVisible(true)
setFloatContainerCollapsed(false)
}
}
}}
onMouseEnter={(event, id, item) => {
timerRef2.current = setTimeout(() => {
// hover 到一级菜单时,如果有二级菜单,则显示浮动菜单,并且更新选中的菜单项
if (item.children && item.children.length > 0) {
setSelectMenuId(id)
setFloatContainerVisible(true)
}
// 如果没有二级菜单,并且激活的一级菜单有二级菜单,则将选中的菜单项设置为激活的一级菜单
else if (
(data.find((item) => item.id === activeParentId)?.children?.length || 0) > 0
) {
setSelectMenuId(activeParentId)
if (floatContainerCollapsed) {
setFloatContainerVisible(false)
}
}
}, 200)
if (timerRef.current) {
clearTimeout(timerRef.current)
}
}}
onMouseLeave={(event, id, item) => {
if (timerRef2.current) {
clearTimeout(timerRef2.current)
}
// 当鼠标离开菜单时,将当前选中的菜单项设置为父级菜单项
if (
!sideMenuRef.current?.contains(event.relatedTarget as Node) &&
!floatContainerRef.current?.contains(event.relatedTarget as Node) &&
!siderRef.current?.contains(event.relatedTarget as Node)
) {
// 如果选中的菜单项不是激活的一级菜单,并且激活的一级菜单有二级菜单,或者浮动菜单折叠,则将选中的菜单项设置为激活的一级菜单
if (
(id !== activeParentId &&
(data.find((item) => item.id === activeParentId)?.children?.length || 0) >
0) ||
floatContainerCollapsed
) {
setSelectMenuId(activeParentId)
}
}
timerRef.current = setTimeout(() => {
setFloatContainerVisible(false)
}, 200)
}}
data={data}
/>
} mini={collapsed}>
使用手册
用户名
admin@example.com
}
footer={ setProfileVisible(false)}>退出登录
}
settings={{
value: settingsValue,
data: [
{
id: 'timezone',
title: '时区',
subtitle: 'UTC+08:00',
children: [
{ id: 'timezone-1', title: '时区1' },
{ id: 'timezone-2', title: '时区2' },
{ id: 'timezone-3', title: '时区3' },
],
},
{
id: 'language',
title: '语言',
subtitle: '中文',
children: [
{ id: 'language-1', title: '语言1' },
{ id: 'language-2', title: '语言2' },
{ id: 'language-3', title: '语言3' },
],
},
],
onItemClick: (evt, item) => {
// evt.preventDefault()
},
onChange: (value) => {
setSettingsValue(value)
setProfileVisible(false)
},
}}
onClose={() => setProfileVisible(false)}
>
setProfileVisible(!profileVisible)}
>
{collapsed ? null :
用户名}
{
setFloatContainerCollapsed(collapsed)
if (collapsed) {
setFloatContainerVisible(false)
} else {
setFloatContainerVisible(true)
}
}}
onMouseEnter={() => {
setFloatContainerVisible(true)
if (timerRef.current) {
clearTimeout(timerRef.current)
}
}}
onMouseLeave={(event) => {
timerRef.current = setTimeout(() => {
setFloatContainerVisible(false)
}, 200)
// 当鼠标离开菜单时,将当前选中的菜单项设置为父级菜单项
if (
!sideMenuRef.current?.contains(event.relatedTarget as Node) &&
!floatContainerRef.current?.contains(event.relatedTarget as Node) &&
!siderRef.current?.contains(event.relatedTarget as Node)
) {
// 如果激活的一级菜单有二级菜单,或者浮动菜单折叠,则将选中的菜单项设置为激活的一级菜单
if (
(data.find((item) => item.id === activeParentId)?.children?.length || 0) > 0 ||
floatContainerCollapsed
) {
setSelectMenuId(activeParentId)
}
}
}}
>
{
setActiveMenuId(id)
}}
/>
} />
}>
主操作
}
/>
>
)
}
```
### 顶部导航栏
```tsx
import React from 'react'
import { SearchOutlined, BellOutlined, AppStoreFilled, MenuOutlined } from '@hi-ui/icons'
import { Button, Avatar, EllipsisTooltip, TabList } from '@hi-ui/hiui'
import Layout, { Header, Content, AppListPopover, ProfilePopover } from '@hi-ui/layout'
export const WithHeader = () => {
const [appListPopoverVisible, setAppListPopoverVisible] = React.useState(false)
const [activeAppId, setActiveAppId] = React.useState(undefined)
const [profileVisible, setProfileVisible] = React.useState(false)
const [settingsValue, setSettingsValue] = React.useState({})
return (
<>
} appearance="text" size="sm" />
} appearance="text" size="sm" />
,
iconBgColor: 'BLUE',
id: 1,
title: '应用1',
},
{
icon: 'Y',
iconBgColor: 'SKYBLUE',
id: 2,
title: '应用2',
},
{
icon: '',
iconBgColor: 'CYAN',
id: 3,
title: '应用3',
},
{
iconBgColor: 'GREEN',
id: 4,
title: '很长很长很长很长很长的应用名称',
},
{
iconBgColor: 'PURPLE',
id: 5,
title: '应用5',
},
{
iconBgColor: 'YELLOW',
id: 6,
title: '应用6',
},
{
iconBgColor: 'ORANGE',
id: 7,
title: '应用7',
},
{
iconBgColor: 'BLUE',
id: 8,
title: '应用8',
},
]}
titleRender={(item) => {
return
{item.title as string}
}}
onItemClick={(item) => {
setActiveAppId(item.id)
setAppListPopoverVisible(false)
}}
onOutsideClick={() => setAppListPopoverVisible(false)}
>
}
appearance="text"
size="sm"
onClick={() => {
setAppListPopoverVisible(!appListPopoverVisible)
}}
/>
用户名
admin@example.com
}
footer={ setProfileVisible(false)}>退出登录
}
settings={{
value: settingsValue,
data: [
{
id: 'timezone',
title: '时区',
subtitle: 'UTC+08:00',
children: [
{ id: 'timezone-1', title: '时区1' },
{ id: 'timezone-2', title: '时区2' },
{ id: 'timezone-3', title: '时区3' },
],
},
{
id: 'language',
title: '语言',
subtitle: '中文',
children: [
{ id: 'language-1', title: '语言1' },
{ id: 'language-2', title: '语言2' },
{ id: 'language-3', title: '语言3' },
],
},
],
onItemClick: (evt, item) => {
// evt.preventDefault()
},
onChange: (value) => {
setSettingsValue(value)
setProfileVisible(false)
},
}}
onClose={() => setProfileVisible(false)}
>
setProfileVisible(!profileVisible)}
/>
>
)
}
```
## Props
### Layout Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------- | -------- | ----------------- | ----------------- | ------ |
| direction | 布局方向 | "row" \| "column" | "row" \| "column" | "row" |
### Sider Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | -------------- | ------------------------------ | ------------- | ------ |
| width | 宽度 | number | - | - |
| maxWidth | 最大宽度 | number | - | - |
| resizable | 是否可调整宽度 | boolean | true \| false | true |
| collapsed | 是否折叠 | boolean | true \| false | - |
| onCollapse | 折叠回调 | ((collapsed: boolean) => void) | - | - |
### SearchTrigger Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------------- | -------- | --------------------------------------------- | ------------------------------- | ------ |
| mini | 迷你模式 | boolean | true \| false | - |
| innerRef | | RefObject\ | - | - |
| clearText | | ReactNode | - | - |
| notFoundContent | | ReactNode | - | - |
| width | | Width\ | string \| number \| string & {} | - |
| visible | | boolean | true \| false | - |
| data | | MenuDataItem\[] | - | - |
| defaultValue | | string | - | "" |
| value | | string | - | - |
| onChange | | ((value: string) => void) | - | - |
| onSearch | | ((value: string) => void) | - | - |
| onSelect | | ((id: ReactText, item: MenuDataItem) => void) | - | - |
| onClear | | (() => void) | - | - |
| onClose | | (() => void) | - | - |
| onEsc | | (() => void) | - | - |
| classNames | | MenuSearchSemanticClassNames | - | - |
| styles | | MenuSearchSemanticStyles | - | - |
### FloatMenuContainer Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | -------- | ------------------------------ | ------------- | ------ |
| width | 浮动宽度 | number | - | - |
| zIndex | 层级 | number | - | - |
| visible | 是否显示 | boolean | true \| false | - |
| collapsed | 是否折叠 | boolean | true \| false | - |
| onCollapse | 折叠回调 | ((collapsed: boolean) => void) | - | - |
### AppList Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------------- | ----------------- | ----------------------------------------------------------------------------- | ------ | ------ |
| data | 应用列表数据 | AppListItem\[] | - | - |
| defaultActiveId | 默认激活的应用 id | ReactText | - | - |
| activeId | 激活的应用 id | ReactText | - | - |
| titleRender | 应用标题渲染 | ((item: AppListItem) => ReactNode) | - | - |
| onItemClick | 应用列表点击回调 | ((item: AppListItem, event: MouseEvent\) => void) | - | - |
### AppListPopover Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| visible | 应用列表是否可见 | boolean | true \| false | - |
| onOpen | 应用列表打开回调 | (() => void) | - | - |
| onClose | 应用列表关闭回调 | (() => void) | - | - |
| data | 应用列表数据 | AppListItem\[] | - | - |
| defaultActiveId | 默认激活的应用 id | ReactText | - | - |
| activeId | 激活的应用 id | ReactText | - | - |
| titleRender | 应用标题渲染 | ((item: AppListItem) => ReactNode) | - | - |
| onItemClick | 应用列表点击回调 | ((item: AppListItem, event: MouseEvent\) => void) | - | - |
| title | 气泡卡片标题 | ReactNode | - | - |
| innerRef | | Ref\ | - | - |
| classNames | | PopoverSemanticClassNames | - | - |
| styles | | PopoverSemanticStyles | - | - |
| zIndex | 手动指定 css 展示层级 | number | - | - |
| matchWidth | 自动计算匹配吸附元素的宽度与其一致 | boolean | true \| false | - |
| placement | 相对吸附元素的位置 | PopperPlacementEnum | "auto" \| "auto-start" \| "auto-end" \| "top" \| "bottom" \| "right" \| "left" \| "top-start" \| "top-end" \| "bottom-start" \| "bottom-end" \| "right-start" \| "right-end" \| "left-start" \| "left-end" | - |
| container | 指定 portal 的容器 | HTMLElement \| (() => HTMLElement \| null) \| null | null \| HTMLElement \| () => HTMLElement \| null | - |
| disabledPortal | 禁用 portal | boolean | true \| false | - |
| arrow | 是否展示箭头 | boolean | true \| false | - |
| onOutsideClick | 外界元素点击数触发 | ((evt: SyntheticEvent\) => void) | - | - |
| closeOnOutsideClick | 开启点击外部时触发 onClose 回调
TODO: 移除,使用失焦控制 | boolean | true \| false | - |
| onEnter | 开始动画弹出时回调 | (() => void) | - | - |
| onEntered | 结束动画弹出时回调 | (() => void) | - | - |
| onExit | 开始动画隐藏时回调 | (() => void) | - | - |
| onExited | 结束动画隐藏时回调 | (() => void) | - | - |
| crossGap | 设置基于 reference 元素的正交偏移量 | number | - | - |
| modifiers | 自定义 popper.js 的装饰器 | readonly Partial\>\[] | - | - |
| shouldWrapChildren | 使用标签强制包裹 children,使触发器支持 trigger 的事件 | boolean | true \| false | - |
| autoWrapChildren | 使用标签自动包裹 children,使触发器支持 trigger 的事件 | boolean | true \| false | - |
| wrapTagName | 指定包裹 children 的标签 | ElementType\ | - | - |
| attachEl | 吸附的元素 | HTMLElement | - | - |
| showTitleDivider | 显示标题分割线 | boolean | true \| false | - |
| trigger | 气泡卡片触发方式 | PopoverTriggerActionEnum \| PopoverTriggerActionEnum\[] | "click" \| "contextmenu" \| "hover" \| "focus" \| PopoverTriggerActionEnum\[] | - |
| mouseEnterDelay | 鼠标移入展示延时,单位:毫秒 | number | - | - |
| mouseLeaveDelay | 鼠标移出后隐藏延时,单位:毫秒 | number | - | - |
| gutterGap | 设置基于 reference 元素的间隙偏移量 | number | - | - |
| popperClassName | 自定义 Popper 的 className | string | - | - |
### Profile Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| -------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| header | | ReactNode | - | - |
| footer | | ReactNode | - | - |
| settings | | { value?: Record\; data: ProfileSettingsItem\[]; placement?: PopperPlacementEnum; onItemClick?: ((evt: MouseEvent<...>, item: ProfileSettingsItem) => void) \| undefined; onChange?: ((value: Record<...>, targetItem: ProfileSettingsItem) => void) \| undefined; } \| undefined | { value?: Record\ \| undefined; data: ProfileSettingsItem\[]; placement?: PopperPlacementEnum; onItemClick?: ((evt: MouseEvent<...>, item: ProfileSettingsItem) => void) \| undefined; onChange?: ((value: Record<...>, targetItem: ProfileSettingsItem) => void) \| undefined; } | - |
### ProfilePopover Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| header | | ReactNode | - | - |
| footer | | ReactNode | - | - |
| settings | | { value?: Record\; data: ProfileSettingsItem\[]; placement?: PopperPlacementEnum; onItemClick?: ((evt: MouseEvent<...>, item: ProfileSettingsItem) => void) \| undefined; onChange?: ((value: Record<...>, targetItem: ProfileSettingsItem) => void) \| undefined; } \| undefined | { value?: Record\ \| undefined; data: ProfileSettingsItem\[]; placement?: PopperPlacementEnum; onItemClick?: ((evt: MouseEvent<...>, item: ProfileSettingsItem) => void) \| undefined; onChange?: ((value: Record<...>, targetItem: ProfileSettingsItem) => void) \| undefined; } | - |
| title | 气泡卡片标题 | ReactNode | - | - |
| onClose | 关闭时回调 | (() => void) | - | - |
| innerRef | | Ref\ | - | - |
| visible | 控制气泡卡片的显示和隐藏(受控) | boolean | true \| false | - |
| classNames | | PopoverSemanticClassNames | - | - |
| styles | | PopoverSemanticStyles | - | - |
| zIndex | 手动指定 css 展示层级 | number | - | - |
| onOpen | 打开时回调 | (() => void) | - | - |
| matchWidth | 自动计算匹配吸附元素的宽度与其一致 | boolean | true \| false | - |
| placement | 相对吸附元素的位置 | PopperPlacementEnum | "auto" \| "auto-start" \| "auto-end" \| "top" \| "bottom" \| "right" \| "left" \| "top-start" \| "top-end" \| "bottom-start" \| "bottom-end" \| "right-start" \| "right-end" \| "left-start" \| "left-end" | "right-end" |
| container | 指定 portal 的容器 | HTMLElement \| (() => HTMLElement \| null) \| null | null \| HTMLElement \| () => HTMLElement \| null | - |
| disabledPortal | 禁用 portal | boolean | true \| false | - |
| arrow | 是否展示箭头 | boolean | true \| false | - |
| onOutsideClick | 外界元素点击数触发 | ((evt: SyntheticEvent\) => void) | - | - |
| closeOnOutsideClick | 开启点击外部时触发 onClose 回调
TODO: 移除,使用失焦控制 | boolean | true \| false | - |
| onEnter | 开始动画弹出时回调 | (() => void) | - | - |
| onEntered | 结束动画弹出时回调 | (() => void) | - | - |
| onExit | 开始动画隐藏时回调 | (() => void) | - | - |
| onExited | 结束动画隐藏时回调 | (() => void) | - | - |
| crossGap | 设置基于 reference 元素的正交偏移量 | number | - | - |
| modifiers | 自定义 popper.js 的装饰器 | readonly Partial\>\[] | - | - |
| shouldWrapChildren | 使用标签强制包裹 children,使触发器支持 trigger 的事件 | boolean | true \| false | - |
| autoWrapChildren | 使用标签自动包裹 children,使触发器支持 trigger 的事件 | boolean | true \| false | - |
| wrapTagName | 指定包裹 children 的标签 | ElementType\ | - | - |
| attachEl | 吸附的元素 | HTMLElement | - | - |
| showTitleDivider | 显示标题分割线 | boolean | true \| false | - |
| trigger | 气泡卡片触发方式 | PopoverTriggerActionEnum \| PopoverTriggerActionEnum\[] | "click" \| "contextmenu" \| "hover" \| "focus" \| PopoverTriggerActionEnum\[] | "click" |
| mouseEnterDelay | 鼠标移入展示延时,单位:毫秒 | number | - | - |
| mouseLeaveDelay | 鼠标移出后隐藏延时,单位:毫秒 | number | - | - |
| gutterGap | 设置基于 reference 元素的间隙偏移量 | number | - | - |
| popperClassName | 自定义 Popper 的 className | string | - | - |
### ActionItem Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---- | ---- | --------- | ------------- | ------ |
| icon | | ReactNode | - | - |
| mini | | boolean | true \| false | - |
# List 列表
通用列表。
## 使用示例
### 基础用法
常用在数据管理、信息展示等领域
```tsx
import React from 'react'
import List from '@hi-ui/list'
export const Basic = () => {
return (
<>
{
return
}}
/>
{
return
}}
/>
>
)
}
```
### 不带分割线
```tsx
import React from 'react'
import List from '@hi-ui/list'
export const NoSplit = () => {
return (
<>
{
return
}}
/>
{
return
}}
/>
>
)
}
```
### 列表头部
```tsx
import React from 'react'
import List from '@hi-ui/list'
export const Header = () => {
return (
<>
列表头部
}
data={[
{
title: '1、当前这里是标题信息',
},
{
title: '2、当前这里是标题信息',
},
{
title: '3、当前这里是标题信息',
},
]}
render={(dataItem) => {
return
}}
/>
列表头部
}
data={[
{
title: '1、当前这里是标题信息',
},
{
title: '2、当前这里是标题信息',
},
{
title: '3、当前这里是标题信息',
},
]}
render={(dataItem) => {
return
}}
/>
>
)
}
```
### 带操作
可通过 actionPlacement 配置操作项的垂直对齐位置
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import List from '@hi-ui/list'
export const Action = () => {
return (
<>
操作
),
},
{
title: '当前这里是标题信息',
description:
'这里是一段比较长的描述信息这里是一段比较长的描述信息这里是一段比较长的描述信息',
avatar: 'https://xiaomi.github.io/hiui/logo.png',
action: (
),
},
{
title: '当前这里是标题信息',
description:
'这里是一段比较长的描述信息这里是一段比较长的描述信息这里是一段比较长的描述信息',
avatar: 'https://xiaomi.github.io/hiui/logo.png',
action: (
),
},
]}
render={(dataItem) => {
return
}}
/>
>
)
}
```
### 带分页
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import List from '@hi-ui/list'
export const Pagination = () => {
return (
<>
操作
),
},
{
title: '当前这里是标题信息',
description:
'这里是一段比较长的描述信息这里是一段比较长的描述信息这里是一段比较长的描述信息',
avatar: 'https://xiaomi.github.io/hiui/logo.png',
action: (
),
},
{
title: '当前这里是标题信息',
description:
'这里是一段比较长的描述信息这里是一段比较长的描述信息这里是一段比较长的描述信息',
avatar: 'https://xiaomi.github.io/hiui/logo.png',
action: (
),
},
]}
pagination={{
total: 200,
pageSize: 10,
placement: 'right',
}}
render={(dataItem) => {
return
}}
/>
>
)
}
```
### 数据为空
```tsx
import React from 'react'
import List from '@hi-ui/list'
import EmptyState from '@hi-ui/empty-state'
export const Empty = () => {
return (
<>
{
return
}}
emptyContent={() => }
/>
>
)
}
```
### 自定义头像
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import List from '@hi-ui/list'
import Avatar from '@hi-ui/avatar'
export const CustomAvatar = () => {
return (
<>
操作
),
},
{
title: '当前这里是标题信息',
description:
'这里是一段比较长的描述信息这里是一段比较长的描述信息这里是一段比较长的描述信息',
avatar: 'http://i1.mifile.cn/f/i/hiui/docs/card/pic_2.png',
action: (
),
},
{
title: '当前这里是标题信息',
description:
'这里是一段比较长的描述信息这里是一段比较长的描述信息这里是一段比较长的描述信息',
avatar: 'http://i1.mifile.cn/f/i/hiui/docs/card/pic_3.png',
action: (
),
},
]}
render={(dataItem) => (
}
extra={
}
/>
)}
/>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List, { ListSemanticName } from '@hi-ui/list'
export const Semantic = () => {
const [selected, setSelected] = useState()
return (
<>
{
return
}}
classNames={{
root: 'my-list__root',
header: 'my-list__header',
wrapper: 'my-list__wrapper',
item: 'my-list__item',
pagination: 'my-list__pagination',
}}
styles={{
[selected as string]: {
outline: '1px solid #ffbe0a',
},
}}
pagination={{
total: 200,
pageSize: 10,
placement: 'right',
}}
/>
{
return (
{
setSelected(dataItem.title as ListSemanticName)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### List Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ----------------- | --------------------------------------------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| data *(required)* | 列表展示的数据 | ListDataItem\[] | - | - |
| fieldNames | 设置data中的每一项对应的key | HiBaseFieldNames | - | - |
| render | 自定义渲染列表项 | ((item: ListDataItem) => ReactNode) | - | - |
| split | 是否展示分割线 | boolean | true \| false | true |
| pagination | 对应的 pagination 配置, 设置 undefined 不显示 | (PaginationProps & { placement: ListPaginationPlacementEnum; }) | PaginationProps & { placement: ListPaginationPlacementEnum; } | - |
| bordered | 是否展示边框 | boolean | true \| false | - |
| emptyContent | 数据为空时的展示内容 | ReactNode \| (() => ReactNode) | null \| string \| number \| false \| true \| {} \| ReactElement\> \| ReactNodeArray \| ReactPortal \| () => ReactNode | - |
| header | 列表头部 | ReactNode | - | - |
| classNames | | ListSemanticClassNames | - | - |
| styles | | ListSemanticStyles | - | - |
### ListItem Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------------- | ---------------------- | ----------------------- | ----------------------------- | ------ |
| title | 列表元素的标题 | ReactNode | - | - |
| description | 列表元素的描述内容 | ReactNode | - | - |
| extra | 额外内容 | ReactNode | - | - |
| avatar | 左侧图片 | ReactNode | - | - |
| action | 右侧操作项 | ReactNode | - | - |
| actionPlacement | 右侧操作项垂直对齐位置 | ListActionPlacementEnum | "top" \| "center" \| "bottom" | "top" |
## Type
### ListDataItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------------- | ---------------------- | ----------------------- | ----------------------------- | -------- |
| title | 列表元素的标题 | ReactNode | - | - |
| description | 列表元素的描述内容 | ReactNode | - | - |
| extra | 额外内容 | ReactNode | - | - |
| avatar | 左侧图片资源地址 | string | - | - |
| action | 右侧操作项 | ReactNode | - | - |
| actionPlacement | 右侧操作项垂直对齐位置 | ListActionPlacementEnum | "top" \| "center" \| "bottom" | "center" |
### PaginationProps
> 继承 Pagination 组件的 Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------- | ------------------ | --------------------------- | ---------------------------- | ------- |
| placement | 指定分页显示的位置 | ListPaginationPlacementEnum | 'left' \| 'middle' \|'right' | 'right' |
# Loading 动效加载
用于请求和数据加载成功的中间状态,缓冲用户的等待焦虑。
## 使用示例
### 基础用法
耐心等待,正拼力加载…
```tsx
import React from 'react'
import Loading from '@hi-ui/loading'
export const Basic = () => {
const loadingIdRef = React.useRef(null)
React.useEffect(() => {
return () => {
Loading.close(loadingIdRef.current)
}
}, [])
return (
<>
>
)
}
```
### 文案位置
```tsx
import React from 'react'
import Loading from '@hi-ui/loading'
export const ContentPosition = () => {
const loadingIdRef = React.useRef(null)
React.useEffect(() => {
return () => {
Loading.close(loadingIdRef.current)
}
}, [])
return (
<>
>
)
}
```
### API调用
```tsx
import React from 'react'
import Loading from '@hi-ui/loading'
import Button from '@hi-ui/button'
export const Duration = () => {
const loadingIdRef = React.useRef(null)
React.useEffect(() => {
return () => {
Loading.close(loadingIdRef.current)
}
}, [])
return (
<>
>
)
}
```
### 局部容器加载
```tsx
import React from 'react'
import Loading from '@hi-ui/loading'
export const Visible = () => {
const [visible, setVisible] = React.useState(false)
return (
<>
{
setVisible((prev) => !prev)
}}
style={{
width: 500,
height: 300,
boxSizing: 'border-box',
background: '#f5f7fa',
padding: 20,
border: '20px solid #5f6a7a',
}}
/>
>
)
}
```
### 无蒙层
```tsx
import React from 'react'
import Loading from '@hi-ui/loading'
export const Mask = () => {
const loadingIdRef = React.useRef(null)
React.useEffect(() => {
return () => {
Loading.close(loadingIdRef.current)
}
}, [])
return (
<>
>
)
}
```
### 设置加载类型
```tsx
import React from 'react'
import Loading from '@hi-ui/loading'
export const Type = () => {
return (
<>
>
)
}
```
### 加载提示
与 Message 结合使用
```tsx
import React from 'react'
import Button from '@hi-ui/button'
import message from '@hi-ui/message'
import Spinner from '@hi-ui/spinner'
export const WithToast = () => {
const [loading, setLoading] = React.useState(false)
const handleSubmit = () => {
setLoading(true)
setTimeout(() => {
setLoading(false)
}, 5000)
}
return (
<>
>
)
}
```
### 自定义样式
通过 classNames 和 styles 属性,可以对组件进行更细粒度的样式控制
```tsx
import React, { useState } from 'react'
import { Row, Col } from '@hi-ui/grid'
import List from '@hi-ui/list'
import Loading from '@hi-ui/loading'
export const Semantic = () => {
const [selected, setSelected] = useState<
'root' | 'mask' | 'content-wrapper' | 'icon' | 'content' | 'wrapper'
>()
return (
<>
{
return (
{
setSelected(dataItem.title as any)
}}
onMouseLeave={() => {
setSelected(undefined)
}}
>
)
}}
/>
>
)
}
```
## Props
### Loading Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------------- | ---------------------------------------- | ------------------------- | --------------------------- | ------ |
| content | 自定义加载中状态的文案 | ReactNode | - | - |
| contentPosition | 设置加载中状态的文案位置 | "right" \| "bottom" | "right" \| "bottom" | - |
| visible | 是否开启显示 | boolean | true \| false | - |
| full | 是否全屏展示,开启节点将挂载到 body | boolean | true \| false | - |
| delay | 延迟显示加载效果的时长(可用于防止闪烁) | number | - | - |
| size | 设置尺寸 | LoadingSizeEnum | Omit\ | - |
| color | 设置颜色,仅在 type 为 spin 时有效 | Color | - | - |
| type | loading 效果类型 | "dot" \| "spin" | "dot" \| "spin" | - |
| showMask | 设置蒙层 | boolean | true \| false | - |
| wrapperClassName | 设置包裹器类名 | string | - | - |
| wrapperStyle | 设置包裹器样式 | CSSProperties | - | - |
| classNames | | LoadingSemanticClassNames | - | - |
| styles | | LoadingSemanticStyles | - | - |
## Methods
### Loading.open(target, { content, size, duration, autoClose })
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --------- | --------------------------------------------- | ------------------- | -------------------- | ------ |
| target | 需要 `Loading` 遮罩的元素, 当不传时为全屏遮罩 | HTMLElement \| null | - | - |
| content | 自定义加载中状态的文案 | ReactNode | - | - |
| duration | loading 自动关闭的时间,单位为毫秒 | number | - | - |
| size | loading 的尺寸 | LoadingSizeEnum | 'lg' \| 'md' \| 'sm' | 'md' |
| autoClose | 是否开启 loading 自动关闭 | boolean | true \| false | - |
### Loading.close(key)
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---- | ------------------------------------ | ------ | ------ | ------ |
| key | open 方法返回的 Loading 实例唯一标识 | string | - | - |
# LocaleContext 语言上下文
语言设置上下文。
## 使用示例
### 基础用法
```tsx
import React, { useContext } from 'react'
import { LocaleContext } from '@hi-ui/locale-context'
export const Basic = () => {
const i18n = useContext(LocaleContext)
return (
<>
{i18n.get('datePicker.ok')}
>
)
}
```
## Props
### getLanguage Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------------------------- | ---- | -------------------- | ------ | ------ |
| timePicker *(required)* | | Record\ | - | - |
| datePicker *(required)* | | Record\ | - | - |
| pagination *(required)* | | Record\ | - | - |
| cascader *(required)* | | Record\ | - | - |
| checkCascader *(required)* | | Record\ | - | - |
| select *(required)* | | Record\ | - | - |
| selectTree *(required)* | | Record\ | - | - |
| search *(required)* | | Record\ | - | - |
| transfer *(required)* | | Record\ | - | - |
| upload *(required)* | | Record\ | - | - |
| modal *(required)* | | Record\ | - | - |
| tabs *(required)* | | Record\ | - | - |
| timeline *(required)* | | Record\ | - | - |
| form *(required)* | | Record\ | - | - |
| tree *(required)* | | Record\ | - | - |
| table *(required)* | | Record\ | - | - |
| watermark *(required)* | | Record\ | - | - |
| emptyState *(required)* | | Record\ | - | - |
| checkSelect *(required)* | | Record\ | - | - |
| treeSelect *(required)* | | Record\ | - | - |
| checkTreeSelect *(required)* | | Record\ | - | - |
| picker *(required)* | | Record\ | - | - |
| zenMode *(required)* | | Record\ | - | - |
| popConfirm *(required)* | | Record\ | - | - |
| tag *(required)* | | Record\ | - | - |
| backTop *(required)* | | Record\ | - | - |
| menuSearch *(required)* | | Record\