跳转到内容

Sortable 排序

通过拖拽或键盘重新排列内容。

用法

拖动任务调整顺序

组件结构

加粗的是必需部件。

data-scope="sortable"root · item · item-drag-trigger · drop-indicator · live-region

示例

水平排序

调整标签顺序

网格排序

在换行布局中排序

禁用项目

固定单个项目的位置

设计指引

何时使用

  • 调整任务、标签页、收藏项或表格列的顺序。
  • 需要保存用户定义的排列顺序。

何时不用

  • 数据规则决定顺序时使用普通排序。
  • 跨容器拖拽需要使用更完整的拖放方案。

特性

  • 支持垂直、水平和换行网格排序。
  • 拖动时实时显示让位和落点。
  • 支持边缘自动滚动。
  • sort 事件返回重排后的 ids

组合

  • 可在项目中放置独立拖拽手柄。
  • 可与表格组合为列排序面板。

最佳实践

  • 拖拽手柄放在项目的固定位置,与项目内的其他控件分开。
  • 拖放结束后立刻持久化 ids,失败时回滚并提示。
  • 项目高度保持一致,让位动画才能表达落点。

反模式

  • 用整个项目作为手柄,项目内的按钮与链接将无法点击。
  • 拖动中改变列表长度或过滤条件。

API 参考

产物

自定义元素<xh-sortable>
Vue 组件XhSortableDropIndicator XhSortableItem XhSortableItemDragTrigger XhSortableLiveRegion XhSortableRoot
组合式函数useSortable
状态机sortableMachine
皮肤@xihan-ui/styles/sortable.css

Props

属性类型必填说明
idsstring[]项的稳定标识,数组顺序即当前顺序。这是顺序的唯一真源。 DOM 中项的先后必须与它一致:几何按 DOM 测量,回调按它计算。
orientationSortableAxis排序沿哪根轴进行。换行网格使用 both
disabledboolean
activationDistancenumber按下之后移动多远才视为开始拖动,默认 5px。提供 0 表示按下即拖动。
autoScrollboolean拖到容器边缘时自动滚动,默认开启。
dirDirection
translationsPartial<SortableTranslations>
onSort(details: SortableSortDetails) => void顺序变化意图。取消的一次不发出。
onDragStart(details: SortableDragStartDetails) => void
onDragEnd(details: SortableDragEndDetails) => void

事件

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
sortSortableSortDetails顺序变化;detail 为 { from, to, id, ids },其中 ids 已重排
drag-startSortableDragStartDetails拾起;detail 为 { id, from, mode }
drag-endSortableDragEndDetails收尾(含取消);detail 为 { id, from, to, mode, canceled }

插槽

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhSortableItemdefaultSortableItemSlotProps
XhSortableItemDragTriggerdefault
XhSortableRootdefaultSortableRootSlotProps

状态

以下名称仅用于内部状态机。

状态idle · pending · dragging

事件ITEM.POINTER_DOWN · POINTER.MOVE · POINTER.END · POINTER.CANCEL · ITEM.PICKUP · KEY.MOVE · KEY.DROP · KEY.CANCEL · PRESS.START · PRESS.END

判据canSort · passedActivation · canPress

connect API

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
draggingboolean正在拖(含键盘拖动)。
activeIdstring | null
fromnumber
tonumber
modeSortableMode | null
itemsSortableItemState[]逐项的呈现状态,顺序与 ids 一致。
getRootProps() => T['element']
getItemProps(props: SortableItemProps) => T['element']
getItemDragTriggerProps(props: SortableItemProps) => T['element']
getDropIndicatorProps() => T['element']落点线:拖动中且落点与起点不同位时才存在,位置由内联样式给出。
getLiveRegionProps() => T['element']

无障碍

键盘

规格出处:W3C APG

按键生效条件行为
Space / Enterfocus in item-drag-trigger,未在拖动,not disabled拾起这一项,进入键盘拖动;播报它现在第几位、共几项、以及接下来能按什么
ArrowDown / ArrowRight键盘拖动中往后挪一位并播报新位置;已在末位时不动,也不回绕。竖直排布认上下键、水平排布认左右键,另一条轴上的方向键原样放行
ArrowUp / ArrowLeft键盘拖动中往前挪一位,规则同上;rtl 下左右两键对调,语义恒是「往前 / 往后」
Space / Enter键盘拖动中放下,按当前位置提交顺序并播报落点
Escape键盘拖动中取消,顺序回到拾起前,播报已取消与原位置
Enter / Spaceheld on item-drag-trigger, not disabled按住期间把手投影 data-pressed,与指针 :active 同一副按压面;拾起转拖动那一下即撤下(拖动中的回执是 data-dragging),抬起或失焦撤下

ARIA

以下属性由 connect 生成。

部件属性
rootaria-labeltranslations?.root
rootrole'group'
item-drag-triggeraria-disabled'true' | 'false'
item-drag-triggeraria-labeltranslations?.itemDragTrigger?.(name)
item-drag-triggeraria-pressed'true' | 'false'
item-drag-triggeraria-roledescription'sortable'
item-drag-triggerrole'button'
drop-indicatoraria-hidden'true'
live-regionaria-atomic'true'
live-regionaria-live'polite'
live-regionrole'status'
  • 空格拾取或放下,方向键移动,Escape 取消。
  • live-region 会播报当前拖动位置。
  • 拖动期间焦点保留在当前手柄。

样式参考

皮肤

@xihan-ui/styles/sortable.css 使用 [data-scope="sortable"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides

数据属性

connect 生成;条件不成立时不输出无值属性。

部件属性
rootdata-disabled''(条件成立时才出现)
rootdata-dragging''(条件成立时才出现)
rootdata-orientationprops.orientation
itemdata-disabled''(条件成立时才出现)
itemdata-dragging''(条件成立时才出现)
itemdata-indexString(item?.index ?? -1)
item-drag-triggerdata-disabled''(条件成立时才出现)
item-drag-triggerdata-dragging''(条件成立时才出现)
item-drag-triggerdata-pressed''(条件成立时才出现)
item-drag-triggerdata-xh-action-control''
item-drag-triggerdata-xh-action-display'always'
item-drag-triggerdata-xh-action-profile'icon'
item-drag-triggerdata-xh-action-size'xs'
item-drag-triggerdata-xh-action-variant'ghost'
drop-indicatordata-orientationprops.orientation

CSS 变量

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-sortable-drag-bg-activeitem-drag-triggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedsortable 的 item-drag-trigger 部件 background-color 覆盖槽。
--xh-sortable-drag-bg-hoveritem-drag-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hoversortable 的 item-drag-trigger 部件 background-color 覆盖槽。
--xh-sortable-drag-fgitem-drag-triggercolordefault--xh-fg-mutedsortable 的 item-drag-trigger 部件 color 覆盖槽。
--xh-sortable-drag-fg-disableditem-drag-triggercolordisabled--xh-fg-disabledsortable 的 item-drag-trigger 部件 color 覆盖槽。
--xh-sortable-drag-fg-hoveritem-drag-triggercolordisabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-defaultsortable 的 item-drag-trigger 部件 color 覆盖槽。
--xh-sortable-drag-grip-hitem-drag-triggerblock-sizeempty--xh-space-3sortable 的 item-drag-trigger 部件 block-size 覆盖槽。
--xh-sortable-drag-grip-witem-drag-triggerinline-sizeempty--xh-space-1sortable 的 item-drag-trigger 部件 inline-size 覆盖槽。
--xh-sortable-drag-icon-sizeitem-drag-trigger--xh-icon-sizedefault--xh-_action-profile-glyph-sizesortable 的 item-drag-trigger 部件 --xh-icon-size 覆盖槽。
--xh-sortable-drag-radiusitem-drag-triggerborder-radiusdefault--xh-shape-controlsortable 的 item-drag-trigger 部件 border-radius 覆盖槽。
--xh-sortable-drag-sizeitem-drag-triggerblock-size
inline-size
min-inline-size
default
xh-action-profile=icon
--xh-_action-profile-visual-sizesortable 的 item-drag-trigger 部件 block-size、inline-size、min-inline-size 覆盖槽。
--xh-sortable-drop-indicator-bgdrop-indicatorbackgrounddefault--xh-bg-brandsortable 的 drop-indicator 部件 background 覆盖槽。
--xh-sortable-drop-indicator-radiusdrop-indicatorborder-radiusdefault--xh-shape-pillsortable 的 drop-indicator 部件 border-radius 覆盖槽。
--xh-sortable-drop-indicator-sizedrop-indicatorblock-size
inline-size
orientation=both
orientation=horizontal
orientation=vertical
--xh-stroke-thicksortable 的 drop-indicator 部件 block-size、inline-size 覆盖槽。
--xh-sortable-gaprootgapdefault--xh-space-2sortable 的 root 部件 gap 覆盖槽。
--xh-sortable-item-opacity-draggingitemopacitydragging0.9sortable 的 item 部件 opacity 覆盖槽。
--xh-sortable-item-shadow-draggingitembox-shadowdragging--xh-elevation-liftedsortable 的 item 部件 box-shadow 覆盖槽。

动效

box-shadow · opacity · transformtransition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

响应式

皮肤另按输入能力分档:pointer: coarse:同一份皮肤在触屏与带指针的设备上不一样,与视口宽度无关。

RTL

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。

Released under The MIT License