入门
安装
在终端中输入:
# npm
npm i effdnd
# pnpm
pnpm add effdnd
# yarn
yarn add effdnd快速入门
简而言之,effdnd 使用了两个自定义 Web 组件:
effdnd trigger会触发拖放操作,effdnd-actor指示布局中将参与拖放过程的区域(扮演各自的角色)。
Web 组件 effdnd-actor 可以扮演多种角色:
item- 被移动的物品,target- 移动的目标,scope- 移动边界。
要设置角色,需要在 effdnd-actor 元素上设置同名属性。一个元素可以设置多个角色。这些属性值将由 effdnd-trigger 组件用于识别拖放参与者。
在拖放操作开始时,effdnd-trigger Web 组件使用其属性来选择流程中的参与者(actors):
item属性允许您选择要移动的元素。如果未指定该属性,则会使用树中具有指定item属性的最接近的<effdnd-actor item='...'>元素。如果设置了值为#的属性(<effdnd-trigger item='#'>)或上述 DOM 树中不存在<effdnd-actor item='...'>元素,则会移动触发器本身。如果触发器具有clone属性,则会创建一个 HTML 元素的副本用于移动;scope属性允许您选择可用的移动区域。如果未指定该属性,则会使用树中最近的具有指定scope属性的<effdnd-actor scope='...'>。如果设置了值为#的属性(<effdnd-trigger scope='#'>)或上面的 DOM 树中没有<effdnd-actor scope='...'>,则作用域区域将是document.body;target属性允许您选择可用的移动目标。当拖放操作结束时,移动目标会生成特殊事件。位于scope区域内的所有<effdnd-actor target='...'>元素都将被视为移动目标,其名称以触发器的target属性值开头。这意味着,如果未指定该属性,则所有位于<effdnd-actor scope='...'>内的<effdnd-actor target='...'>元素都可用。
要定义这两个 Web 组件,只需调用 useDnD 函数,并使用调用结果创建事件监听器即可。
import { useDnD } from 'effdnd';
// you can pass style parameters to useDnD,
// to override the movement parameters
// (for more information, see the type `TUseDnD`)
const { observe } = useDnD();
export const Component = () => {
const ref = useRef();
useEffect(() => {
// you can subscribe to Drag-and-Drop events
const unobserve = observe((e) => {
// the event is being processed here
}, ref.current);
// and you can unsubscribe
return () => unobserve();
});
return <effdnd-actor scope='top' ref={ref} >
<div className="targets-wrapper">
<effdnd-actor target='target-1'>...</effdnd-actor>
<effdnd-actor target='target-2'>...</effdnd-actor>
</div>
<div id="items-wrapper">
<effdnd-actor item='item-1'>
<effdnd-trigger>Trigger #1</effdnd-trigger>
</effdnd-actor>
<effdnd-actor item='item-2'>
<effdnd-trigger>Trigger #2</effdnd-trigger>
</effdnd-actor>
</div>
</effdnd-actor>;
}主动元件和被动元件
在拖放过程中,effdnd-trigger 会设置选定的 effdnd-actor 元素的动态 state 属性。也就是说,在操作开始时,触发器会确定要移动的元素(item)、移动范围(scope)以及目标位置(target)。 这些元素可以是
- 没有国家,
- 处于被动状态(
state="passive"), - 处于活动状态(
state="active")。
具有 item 角色的元素在移动过程中处于活动状态。此外,如果具有 item 角色的元素的克隆体处于活动状态,则该元素可以处于克隆状态(state="cloned")。
当 item 移动到具有 scope 角色的元素内部时,该元素处于被动状态。
如果具有 scope 角色的元素处于 被动 状态,并且 item 尝试超出该角色范围,则该元素变为 主动 状态。此状态会向用户显示可用的移动范围限制。
当具有 target 角色的元素位于具有活动或被动状态的 scope 内时,该元素处于被动状态。
如果具有 target 角色的物品处于 被动 状态,并且 item 移动到它上面,则该物品变为 主动 状态。
组件样式
<effdnd-actor item='...'> 的外观由触发器在移动过程中使用属性进行设置。您还可以使用属性来设置动画参数、移动轴和最小发射距离。
/**
* DnD trigger attributes
*/
export interface ITriggerAttrs {
/**
* Item name
* @description
* If the value is "#" then it will use `effnd-trigger` as scope
*/
item?: string;
/**
* Bounding scope name
* @description
* If the value is "#" then it will use `document.body` as scope
*/
scope?: string;
/**
* Target name or its prefix
*/
target?: string;
/**
* Triggering distance
*/
dist?: string;
/**
* DnD axis
*/
axis?: string;
/**
* Triggering event
* @description
* Both 'touch' and 'mouse' by default
*/
event?: 'touch' | 'mouse';
/**
* Transition duration
*/
dur?: string;
/**
* Transition delay
*/
del?: string;
/**
* Transition timing-function
*/
tf?: string;
/**
* Item z-index in active state
*/
zi?: string;
/**
* Item opacity in active state
*/
opacity?: string;
/**
* Use item clone while dragging
*/
clone?: boolean;
}Web 组件 effdnd-actor 已包含 target 和 scope 被动和主动状态的初始样式,但您也可以使用 unstyled 属性取消这些样式。同时,<effdnd-actor unstyled="target"> 仅取消 target 的内置样式,<effdnd-actor unstyled="scope"> 仅取消 scope 的内置样式,而 <effdnd-actor unstyled> 则取消所有内置样式。
/**
* DnD actor attributes
*/
export interface IActorAttrs {
/**
* Item name
*/
item?: string;
/**
* Scope name
*/
scope?: string;
/**
* Target name
*/
target?: string;
/**
* Actor state
*/
state?: 'active' | 'passive';
/**
* Reset target state styles
*/
unstyled?: boolean | 'target' | 'scope';
/**
* Display contents
*/
contents?: boolean;
}contents 属性允许您设置 display:contents; 样式。如果添加 unstyled 属性,您可以为不同的状态设置自定义 CSS 样式。
effdnd-actor[target][state=passive] .custom-dnd-target {
outline: 4px solid #646cffaa;
}
effdnd-actor[target][state=active] .custom-dnd-target {
outline: 4px solid #646cffaa;
background: #646cffaa;
}useDnD
该函数接受过渡设置作为第一个参数,自定义样式作为第二个参数。它返回用于监听自定义事件的函数:
export type TEventDetail = {
type: TEventType;
refs: TRefs;
keys: TKeys;
event: MouseEvent | TouchEvent;
};
interface TDnDEvent extends CustomEvent {
detail: TEventDetail;
}
export type TDnDCallback = (event: TDnDEvent) => void;
export type TUseDnD = (defs?: Partial<{
/**
* Duration
*/
dur: number;
/**
* Delay
*/
del: number;
/**
* Transition-timing-function
*/
tf: string;
/**
* Active DnD item z-index
*/
zi: number;
/**
* Active DnD item opacity
*/
opacity: number;
}>) => {
/**
* Observe DnD events
* @param callback - event handler
* @param element - HTML element
*/
observe: (callback: TDnDCallback, element?: HTMLElement) => () => void;
/**
* Unobserve DnD events
* @param callback - event handler
* @param element - HTML element
*/
unobserve: (callback: TDnDCallback, element?: HTMLElement) => void;
};effdnd trigger
触发器 Web 组件包含多个有用的方法和属性。
/**
* DnD trigger element
*/
export interface ITriggerElement extends HTMLElement {
/**
* DnD item y-offset
*/
dndY: number;
/**
* DnD item x-offset
*/
dndX: number;
/**
* DnD item
*/
dndItem: HTMLElement;
/**
* DnD scope
*/
dndScope: HTMLElement;
/**
* DnD targets
*/
dndTargets: Set<HTMLElement>;
/**
* Reset DnD transforms
*/
resetDnD(options?: KeyframeAnimationOptions): Promise<void>;
}