可拖动元素并将其余元素推开

Avatar of Chris Coyier
Chris Coyier 发表

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200美元免费额度!

除了涉及文本区域调整大小句柄等一些深奥技巧之外,可拖动元素是网络上 JavaScript 的领域。例如,单击元素,按住鼠标按钮,拖动鼠标光标,元素随鼠标拖动,释放鼠标按钮以释放元素。或者触摸等效项。幸运的是,这是一个经过充分探索的领域。经过时间考验的工具(如 jQuery UI)提供了 Draggable(以及其他类似方法)来简化此操作。

但最近在尝试实现某种效果(请参阅本文标题)时,我无法让 jQuery UI 完全按照我想要的方式进行操作。但我完成了,以下是如何实现的。

我试图在 Keynote 的侧边栏中重新创建效果,您可以在其中拖动以重新排列幻灯片。以下是完成的效果

使用一些非常基本的 jQuery UI 配置,您可以非常接近。我们在这里使用 Sortable 方法。这专门用于对列表进行排序,这就是我们正在做的事情,有点像同时使用 DraggableDroppable

$(".all-slides").sortable({
  
  axis: "y",
  revert: true,
  scroll: false,
  placeholder: "sortable-placeholder",
  cursor: "move"

});

在类似这样的基本 HTML 上

<div class='all-slides'>

  <div class='slide'>Slide</div>
  <div class='slide'>Slide</div>
  <div class='slide'>Slide</div>

  <!-- etc -->

配置中的“占位符”是一个元素(具有提供的类名),它会插入幻灯片之间,如果您现在释放鼠标按钮,该幻灯片将在该位置放置。您可以使用 CSS 以任何方式对其进行样式设置,因此我使其看起来像 Keynote 中的左侧蓝线。

这里的问题是我们没有获得我们想要的“推开”效果。占位符只是立即显示。最初,我尝试通过使用 @keyframes 动画将占位符的高度从 0 扩展到幻灯片高度,然后使用填充模式保持该高度来解决此问题。这适用于占位符的外观,但 jQuery UI 在占位符消失时会将其从 DOM 中移除,这使得无法实现优雅的退出。

因此,需要一些更深层的技巧。幸运的是,在 Twitter 上抱怨困难之后,AJ Kandy 找到一个方便的示例,正好满足我的需求。

请耐心等待,这有点复杂

  1. 循环遍历所有幻灯片
  2. 创建每个幻灯片的副本
  3. 将幻灯片直接放置在原件的顶部
  4. 隐藏它
  5. 保存对其复制来源幻灯片的引用

然后您仅对原始文件启动 Sortable 方法。然后,当您开始拖动幻灯片时

  1. 隐藏所有原始幻灯片
  2. 显示克隆
  3. 在您四处拖动时,原始文件将以不可见的方式重新排列
  4. 在执行此操作后,将克隆动画设置为这些新位置

拖动停止时

  1. 确保所有克隆都位于正确的最终位置
  2. 再次交换可见性,显示原始文件

花了不少时间来理解并进行调整才能使其完美。在我的示例中,我使用伪元素对幻灯片进行编号,因此还有一些代码用于此。以下是所有内容。

$(".slide").each(function(i) {
  var item = $(this);
  var item_clone = item.clone();
  item.data("clone", item_clone);
  var position = item.position();
  item_clone
  .css({
    left: position.left,
    top: position.top,
    visibility: "hidden"
  })
    .attr("data-pos", i+1);
  
  $("#cloned-slides").append(item_clone);
});

$(".all-slides").sortable({
  
  axis: "y",
  revert: true,
  scroll: false,
  placeholder: "sortable-placeholder",
  cursor: "move",

  start: function(e, ui) {
    ui.helper.addClass("exclude-me");
    $(".all-slides .slide:not(.exclude-me)")
      .css("visibility", "hidden");
    ui.helper.data("clone").hide();
    $(".cloned-slides .slide").css("visibility", "visible");
  },

  stop: function(e, ui) {
    $(".all-slides .slide.exclude-me").each(function() {
      var item = $(this);
      var clone = item.data("clone");
      var position = item.position();

      clone.css("left", position.left);
      clone.css("top", position.top);
      clone.show();

      item.removeClass("exclude-me");
    });
    
    $(".all-slides .slide").each(function() {
      var item = $(this);
      var clone = item.data("clone");
      
      clone.attr("data-pos", item.index());
    });

    $(".all-slides .slide").css("visibility", "visible");
    $(".cloned-slides .slide").css("visibility", "hidden");
  },

  change: function(e, ui) {
    $(".all-slides .slide:not(.exclude-me)").each(function() {
      var item = $(this);
      var clone = item.data("clone");
      clone.stop(true, false);
      var position = item.position();
      clone.animate({
        left: position.left,
        top: position.top
      }, 200);
    });
  }
  
});

以及演示

查看 Chris Coyier 的 CodePen 上的 类似 Keynote 的幻灯片重新排列器 (@chriscoyier)。

额外功能:幻灯片在拖动时会获得一个类,该类会使其大小脉动,就像在 Keynote 中一样。

其他选项

David DeSandro 有一些您可能听说过的项目,这些项目都与在网络上重新排列框有关,例如 MasonryIsotope。他还有一个名为 Packery 的项目,它使用算法将框打包到空间中。连同他的另一个项目 Dragabilly 一起,您可以创建 相同的效果,其中拖动元素会将其他元素移开。我们演示的单轴性质对它来说很容易。

David 复制了我的演示并使其与这些工具一起工作,代码量少了很多

查看 Chris Coyier 的 CodePen 上的 类似 Keynote 的幻灯片重新排列器 - 使用 Packery 和 Draggabilly (@chriscoyier)。


Luke Underwood 也尝试了一下,支持不同大小的块

查看 Luke Underwood 的 CodePen 上的 带过渡和可变高度支持的 jQuery 可排序 (@Snarkie3)。