让 Dragula 显示悬停在元素上的放置位置

Posted

技术标签:

【中文标题】让 Dragula 显示悬停在元素上的放置位置【英文标题】:Have dragula show drop position on hover over element 【发布时间】:2020-01-20 08:57:50 【问题描述】:

我有一个与 dragula 一起使用的拖放功能,以便它创建元素以将元素作为子元素拖放到其中。这个想法是您可以使任何元素成为容纳子项的容器。

我遇到的问题是,在将可拖动元素悬停在上面之前,我不希望放置位置可见。在页面周围拖动元素时,它会呈现所有父容器 - 但我真的希望它在悬停在可以创建它的位置时出现。少量项目不是什么大问题,但是当你有 100 多个项目时,它会导致页面增长并且非常不和谐。

以下是我到目前为止所得到的。非常感谢任何帮助!

var drake;

function setupDragula() 


  var containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));

  var item = Array.prototype.slice.call(document.querySelectorAll(".js-structure-item"));

  var opts = 
    allowNestedContainers: true
  ;
  opts = 
    accepts: function(el, target, source, sibling) 
      // prevent dragged containers from trying to drop inside itself
      return !contains(el, target);
    
  ;

  drake = dragula(
    containers,
    opts
  ).on('drag', function(el) 
    prepareEmptyDropZones();
    el.classList.remove('ex-moved');
  ).on('drop', function(el, container, source) 
    el.classList.add('ex-moved');
    removeEmptyDropZones();
  ).on('cancel', function(el, container, source) 
    removeEmptyDropZones();
  ).on('over', function(el, container) 
    container.classList.add('editing');
    el.classList.add('el-over');
  ).on('out', function(el, container) 
    container.classList.remove('editing');
    el.classList.remove('el-over');
  );


function contains(a, b) 
  return a.contains ?
    a != b && a.contains(b) :
    !!(a.compareDocumentPosition(b) & 16);


function prepareEmptyDropZones() 
  var item = querySelectorAllArray(".js-structure-item");

  item.forEach(function(el) 
    var firstParent = el.querySelector('.js-structure-parent');

    if (firstParent === null) 
      //el.classList.add('empty');
      var emptyParent = document.createElement('div');
      emptyParent.className = "js-structure-parent";
      //emptyParent.classList.add('empty-drop-zone');
      el.appendChild(emptyParent);
     else 
      el.classList.remove('empty');
    
  );
  resetContainers();


function removeEmptyDropZones() 
  var dropZones = querySelectorAllArray(".js-structure-parent");
  dropZones.forEach(function(dropZone) 
    if (dropZone.children.length == 0) 
      dropZone.remove();
    
  );


function resetContainers() 
  drake.containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));


function querySelectorAllArray(selector) 
  return Array.prototype.slice.call(document.querySelectorAll(selector))



document.addEventListener("DOMContentLoaded", function(event) 
  setupDragula();
);
.js-structure-item 
  cursor: move;


.js-structure-item .container 
  margin-bottom: 10px;



/*parent*/

.js-structure-parent 
  padding: 0px 0px 0px 30px;
  /*border: 1px solid red;
        position: relative;*/


.js-structure-parent:empty,
.empty-drop-zone 
  min-height: 20px;
  border: 1px dashed #ccc;


.el-over 
  background-color: green;


.js-structure-item.empty 
  color: #666;
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script>

<div class="js-structure-parent">
  <div class="js-structure-item">
    <div class="container">
      File Folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          File 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 4
        </div>
      </div>
    </div>
  </div>
  <div class="js-structure-item">
    <div class="container">
      Image Folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          Image file 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 4
        </div>
      </div>
    </div>
  </div>
  <div class="js-structure-item">
    <div class="container">
      Document folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          Document file 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 4
        </div>
      </div>
    </div>
  </div>
</div>

【问题讨论】:

【参考方案1】:

var drake;

function setupDragula() 


  var containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));

  var item = Array.prototype.slice.call(document.querySelectorAll(".js-structure-item"));

  var opts = 
    allowNestedContainers: true
  ;
  opts = 
    accepts: function(el, target, source, sibling) 
      // prevent dragged containers from trying to drop inside itself
      return !contains(el, target);
    
  ;

  drake = dragula(
    containers,
    opts
  ).on('drag', function(el) 
    prepareEmptyDropZones();
    el.classList.remove('ex-moved');
  ).on('drop', function(el, container, source) 
    el.classList.add('ex-moved');
    removeEmptyDropZones();
  ).on('cancel', function(el, container, source) 
    removeEmptyDropZones();
  ).on('over', function(el, container) 
    container.classList.add('editing');
    el.classList.add('el-over');
  ).on('out', function(el, container) 
    container.classList.remove('editing');
    el.classList.remove('el-over');
  );


function contains(a, b) 
  return a.contains ?
    a != b && a.contains(b) :
    !!(a.compareDocumentPosition(b) & 16);


function prepareEmptyDropZones() 
  var item = querySelectorAllArray(".js-structure-item");

  item.forEach(function(el) 
    var firstParent = el.querySelector('.js-structure-parent');

    if (firstParent === null) 
      //el.classList.add('empty');
      var emptyParent = document.createElement('div');
      emptyParent.className = "js-structure-parent";
      //emptyParent.classList.add('empty-drop-zone');
      el.appendChild(emptyParent);
     else 
      el.classList.remove('empty');
    
  );
  resetContainers();


function removeEmptyDropZones() 
  var dropZones = querySelectorAllArray(".js-structure-parent");
  dropZones.forEach(function(dropZone) 
    if (dropZone.children.length == 0) 
      dropZone.remove();
    
  );


function resetContainers() 
  drake.containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));


function querySelectorAllArray(selector) 
  return Array.prototype.slice.call(document.querySelectorAll(selector))



document.addEventListener("DOMContentLoaded", function(event) 
  setupDragula();
);
.js-structure-item 
  cursor: move;


.js-structure-item .container 
  margin-bottom: 10px;



/*parent*/

.js-structure-parent 
  padding: 0px 0px 0px 30px;
  /*border: 1px solid red;
        position: relative;*/


.el-over 
  background-color: green;


.js-structure-item.empty 
  color: #666;


.gu-mirror 
  position: fixed !important;
  margin: 0 !important;
  z-index: 9999 !important;
  opacity: 0.8;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
  filter: alpha(opacity=80);

.gu-hide 
  display: none !important;

.gu-unselectable 
  -webkit-user-select: none !important;
  -moz-user-select: none !important;
  -ms-user-select: none !important;
  user-select: none !important;

.js-structure-parent:empty,
.empty-drop-zone 
  min-height: 6px;

.gu-transit 
  opacity: 0.2;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
  filter: alpha(opacity=20);
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script>

<div class="js-structure-parent">
  <div class="js-structure-item">
    <div class="container">
      File Folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          File 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 4
        </div>
      </div>
    </div>
  </div>
  <div class="js-structure-item">
    <div class="container">
      Image Folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          Image file 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 4
        </div>
      </div>
    </div>
  </div>
  <div class="js-structure-item">
    <div class="container">
      Document folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          Document file 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 4
        </div>
      </div>
    </div>
  </div>
</div>

试试这个 :::

var drake;

function setupDragula() 


  var containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));

  var item = Array.prototype.slice.call(document.querySelectorAll(".js-structure-item"));

  var opts = 
    allowNestedContainers: true
  ;
  opts = 
    accepts: function(el, target, source, sibling) 
      // prevent dragged containers from trying to drop inside itself
      return !contains(el, target);
    
  ;

  drake = dragula(
    containers,
    opts
  ).on('drag', function(el) 
    prepareEmptyDropZones();
    el.classList.remove('ex-moved');
  ).on('drop', function(el, container, source) 
    el.classList.add('ex-moved');
    removeEmptyDropZones();
  ).on('cancel', function(el, container, source) 
    removeEmptyDropZones();
  ).on('over', function(el, container) 
    container.classList.add('editing');
    el.classList.add('el-over');
  ).on('out', function(el, container) 
    container.classList.remove('editing');
    el.classList.remove('el-over');
  );


function contains(a, b) 
  return a.contains ?
    a != b && a.contains(b) :
    !!(a.compareDocumentPosition(b) & 16);


function prepareEmptyDropZones() 
  var item = querySelectorAllArray(".js-structure-item");

  item.forEach(function(el) 
    var firstParent = el.querySelector('.js-structure-parent');

    if (firstParent === null) 
      //el.classList.add('empty');
      var emptyParent = document.createElement('div');
      emptyParent.className = "js-structure-parent";
      //emptyParent.classList.add('empty-drop-zone');
      el.appendChild(emptyParent);
     else 
      el.classList.remove('empty');
    
  );
  resetContainers();


function removeEmptyDropZones() 
  var dropZones = querySelectorAllArray(".js-structure-parent");
  dropZones.forEach(function(dropZone) 
    if (dropZone.children.length == 0) 
      dropZone.remove();
    
  );


function resetContainers() 
  drake.containers = Array.prototype.slice.call(document.querySelectorAll(".js-structure-parent"));


function querySelectorAllArray(selector) 
  return Array.prototype.slice.call(document.querySelectorAll(selector))



document.addEventListener("DOMContentLoaded", function(event) 
  setupDragula();
);
.js-structure-item 
  cursor: move;


.js-structure-item .container 
  margin-bottom: 10px;



/*parent*/

.js-structure-parent 
  padding: 0px 0px 0px 30px;
  /*border: 1px solid red;
        position: relative;*/


.el-over 
  background-color: green;


.js-structure-item.empty 
  color: #666;


.gu-mirror 
  position: fixed !important;
  margin: 0 !important;
  z-index: 9999 !important;
  opacity: 0.8;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
  filter: alpha(opacity=80);

.gu-hide 
  display: none !important;

.gu-unselectable 
  -webkit-user-select: none !important;
  -moz-user-select: none !important;
  -ms-user-select: none !important;
  user-select: none !important;

.gu-transit 
  opacity: 0.2;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
  filter: alpha(opacity=20);
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script>

<div class="js-structure-parent">
  <div class="js-structure-item">
    <div class="container">
      File Folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          File 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          File 4
        </div>
      </div>
    </div>
  </div>
  <div class="js-structure-item">
    <div class="container">
      Image Folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          Image file 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Image file 4
        </div>
      </div>
    </div>
  </div>
  <div class="js-structure-item">
    <div class="container">
      Document folder
    </div>
    <div class="js-structure-parent">
      <div class="js-structure-item">
        <div class="container">
          Document file 1
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 2
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 3
        </div>
      </div>
      <div class="js-structure-item">
        <div class="container">
          Document file 4
        </div>
      </div>
    </div>
  </div>
</div>

【讨论】:

这很好用,但现在没有办法将一个项目放入另一个项目以创建子容器。 它遇到了之前发生的问题,我可以放入的所有空元素都是可见的,但我只希望它们在悬停在该区域上时。

以上是关于让 Dragula 显示悬停在元素上的放置位置的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jquery ui 可拖动突出显示悬停时的可放置​​区域

平滑的悬停过渡?

从文档中的任何位置访问当前被鼠标悬停的元素[关闭]

Ng2 Dragula 重新排序相同的数组多个放置区域

ng2-dragula 添加新项目后显示在顶部

区分 ng2-dragula 上的单击或拖动