注册
web

一款好用到爆的可视化拖拽库

嗨,大家好,我是徐小夕,之前一直在研究可视化零代码相关的技术实践,也做了很多可视化搭建的产品,比如:



  • H5-Dooring(页面可视化搭建平台)
  • V6.Dooring(数据大屏可视化平台)
  • formManager(表单搭建引擎)
  • Next-Admin(基于nextjs和antd5.0的中后台管理系统)

最近在研发智能搭建系统(WEP)的时候发现一款非常好用的可视化拖拽插件——draggable。它在 github 上有17.4k star,提供了很多非常精美的拖拽案例, 我们使用它可以轻松实现可视化拖拽,组件排序,网格拖拽等效果,而且浏览器兼容性也非常不错,原生 javascript 开发, 可以轻松集成到 reactvue 等主流框架中。


接下来我就和大家一起介绍一下这款开源插件。



安装与使用


我们可以使用如下方式安装:


# yarn add shopify/draggable
pnpm add shopify/draggable

在项目里使用:


import {
Draggable,
Sortable,
Droppable,
Swappable,
} from 'shopify/draggable'

github地址: https://github.com/Shopify/draggable


接下来我就来和大家分享几个非常有价值的使用案例。


1. 3D效果拖拽



代码实现:


// eslint-disable-next-line import/no-unresolved
import {Draggable} from '@shopify/draggable';

// eslint-disable-next-line shopify/strict-component-boundaries
import Plate from '../../components/Plate';

export default function Home() {
const containerSelector = '#Home .PlateWrapper';
const container = document.querySelector(containerSelector);

if (!container) {
return false;
}

const draggable = new Draggable(container, {
draggable: '.Plate',
});
const plates = new Plate(container);

// --- Draggable events --- //
draggable.on('drag:start', (evt) => {
plates.setThreshold();
plates.setInitialMousePosition(evt.sensorEvent);
});

draggable.on('drag:move', (evt) => {
// rAF seems to cause the animation to get stuck?
// requestAnimationFrame(() => {});
plates.dragWarp(evt.source, evt.sensorEvent);
});

draggable.on('drag:stop', () => {
plates.resetWarp();
});

return draggable;
}

2. 可拖拽的开关效果


2.gif


代码如下:


// eslint-disable-next-line import/no-unresolved
import {Draggable} from '@shopify/draggable';

function translateMirror(mirror, mirrorCoords, containerRect) {
if (mirrorCoords.top < containerRect.top || mirrorCoords.left < containerRect.left) {
return;
}

requestAnimationFrame(() => {
mirror.style.transform = `translate3d(${mirrorCoords.left}px, ${mirrorCoords.top}px, 0)`;
});
}

function calcOffset(offset) {
return offset * 2 * 0.5;
}

export default function DragEvents() {
const toggleClass = 'PillSwitch--isOn';
const containers = document.querySelectorAll('#DragEvents .PillSwitch');

if (containers.length === 0) {
return false;
}

const draggable = new Draggable(containers, {
draggable: '.PillSwitchControl',
delay: 0,
});

let isToggled = false;
let initialMousePosition;
let containerRect;
let dragRect;
let dragThreshold;
let headings;
let headingText;

// --- Draggable events --- //
draggable.on('drag:start', (evt) => {
initialMousePosition = {
x: evt.sensorEvent.clientX,
y: evt.sensorEvent.clientY,
};
});

draggable.on('mirror:created', (evt) => {
containerRect = evt.sourceContainer.getBoundingClientRect();
dragRect = evt.source.getBoundingClientRect();

const containerRectQuarter = containerRect.width / 4;
dragThreshold = isToggled ? containerRectQuarter * -1 : containerRectQuarter;
headings = {
source: evt.originalSource.querySelector('[data-switch-on]'),
mirror: evt.mirror.querySelector('[data-switch-on]'),
};
headingText = {
on: headings.source.dataset.switchOn,
off: headings.source.dataset.switchOff,
};
});

draggable.on('mirror:move', (evt) => {
evt.cancel();
const offsetX = calcOffset(evt.sensorEvent.clientX - initialMousePosition.x);
const offsetY = calcOffset(initialMousePosition.y - evt.sensorEvent.clientY);
const offsetValue = offsetX > offsetY ? offsetX : offsetY;
const mirrorCoords = {
top: dragRect.top - offsetValue,
left: dragRect.left + offsetValue,
};

translateMirror(evt.mirror, mirrorCoords, containerRect);

if (isToggled && offsetValue < dragThreshold) {
evt.sourceContainer.classList.remove(toggleClass);
headings.source.textContent = headingText.off;
headings.mirror.textContent = headingText.off;
isToggled = false;
} else if (!isToggled && offsetValue > dragThreshold) {
evt.sourceContainer.classList.add(toggleClass);
headings.source.textContent = headingText.on;
headings.mirror.textContent = headingText.on;
isToggled = true;
}
});

const triggerMouseUpOnESC = (evt) => {
if (evt.key === 'Escape') {
draggable.cancel();
}
};

draggable.on('drag:start', () => {
document.addEventListener('keyup', triggerMouseUpOnESC);
});

return draggable;
}

3.可拖拽的网格元素


3.gif


源码地址: https://github.com/Shopify/draggable/tree/master/examples/src/content/Droppable/UniqueDropzone


4. 可拖拽的列表


4.gif


源码地址: https://github.com/Shopify/draggable/tree/master/examples/src/content/Sortable/SimpleList


5. 卡牌拖拽效果


5.gif


源码地址: https://github.com/Shopify/draggable/tree/master/examples/src/content/Sortable/Transformed


6. 多容器拖拽效果


6.gif


源码地址: https://github.com/Shopify/draggable/tree/master/examples/src/content/Sortable/MultipleContainers


7. 不规则网格拖拽


7.gif


源码地址:https://github.com/Shopify/draggable/tree/master/examples/src/content/Swappable/Floated


8. 拖拽排序动画


8.gif


源码地址: https://github.com/Shopify/draggable/tree/master/examples/src/content/Plugins/SortAnimation


当然还有很多有意思的拖拽案例, 大家也可以去体验一下。


今天就分享到这啦,祝大家节日快乐, 博学!


如果有收获,记得点赞 + 再看哦, 欢迎在评论区评论, 分享你的收藏干货~




作者:徐小夕
来源:juejin.cn/post/7353877562303021093

0 个评论

要回复文章请先登录注册