HTML5 可拖动列表 - 多个 setData?

Posted

技术标签:

【中文标题】HTML5 可拖动列表 - 多个 setData?【英文标题】:HTML5 Draggable List - multiple setData? 【发布时间】:2016-06-10 15:09:57 【问题描述】:

所以,我有一个乐队列表,我想按顺序组织起来,如下所示:

<li data-band-id='1' draggable='true' class='band-name'>Metallica</li>
<li data-band-id='2' draggable='true' class='band-name'>Slayer</li>
<li data-band-id='3' draggable='true' class='band-name'>Paradise Lost</li>
<li data-band-id='4' draggable='true' class='band-name'>Gojira</li>

我希望能够拖动这些列表项来更改整个列表中每个波段的位置。到目前为止,我有以下 javascript 来执行此操作:

var dragSatMS = null;
function handleDragStart(e) 
    //this.style.color = 'green'; 
    dragSatMS = this;
    e.dataTransfer.effectAllowed = 'move';
    e.dataTransfer.setData('text', this.innerhtml);

function handleDragOver(e) 
    if (e.preventDefault) 
        e.preventDefault(); 
    
    e.dataTransfer.dropEffect = 'move';
    return false;

function handleDragEnter(e) 
    this.classList.add('over');

function handleDragLeave(e) 
  this.classList.remove('over');
  //this.style.color = '#333';

function handleDrop(e) 
  if (e.stopPropagation) 
    e.stopPropagation();
  
  if (dragSatMS != this) 
    dragSatMS.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text');
  
  return false;

function handleDragEnd(e) 
  [].forEach.call(mssatCols, function (mSatCol) 
    mSatCol.classList.remove('over');
     //mSatCol.style.color = '#333';
  );

var mssatCols = document.querySelectorAll('#ms-saturday .band-name');
[].forEach.call(mssatCols, function(msSatCol) 
  msSatCol.addEventListener('dragstart', handleDragStart, false);
  msSatCol.addEventListener('dragenter', handleDragEnter, false);
  msSatCol.addEventListener('dragover', handleDragOver, false);
  msSatCol.addEventListener('dragleave', handleDragLeave, false);
  msSatCol.addEventListener('drop', handleDrop, false);
  msSatCol.addEventListener('dragend', handleDragEnd, false);
);

这非常有效,我可以拖放列表以使它们改变位置并且乐队的名称适当地交换。但是,“data-band-id”属性的值保持不变。我知道这正是我所拥有的代码所做的,这就是我的问题。我想修改代码,以便交换被拖放的乐队的名称“data-band-id”属性的值。

我在 Google 上搜索了很多,但没有找到任何可以告诉我如何在多个值上设置数据的信息,非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

您可以查询这两个项目的attributes 属性并访问data-band-id 的值。一旦你有了这两个值,你就可以调用setAttribute("name", "value") 来更新data-band-id。您更新后的 handleDrop 方法将是:

function handleDrop(e) 
  if (e.stopPropagation) 
    e.stopPropagation();
  
  if (dragSatMS != this) 
    dragSatMS.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text');
    //Get the data-band-id of both items.
    itemToReplaceAttr = this.attributes["data-band-id"].value;
    draggedItemAttr = dragSatMS.attributes["data-band-id"].value;
    //Call "setAttribute" to update the attributes.
    this.setAttribute("data-band-id", draggedItemAttr);
    dragSatMS.setAttribute("data-band-id", itemToReplaceAttr);
  
  return false;

这是一个很好的演示:Fiddle

【讨论】:

以下小提琴进一步支持这个答案:jsfiddle.net/yw07rhcm 非常感谢你们:)【参考方案2】:

Yass 的回答是解决问题的一种方式。

但我现在将向您介绍另一种方法,我在所有关于拖放的教程中都小心避免 - 我相信拖放 API 的使用提供了一个理想的场景,事件委托应该大放异彩 - 但是,迄今为止(据我所知)没有一个流行的教程探索过这种方法。

如果您急于查看我的建议,请参阅this fiddle。

因此,您可以将拖动事件的处理委托给项目的父项ul。而不是将被拖动元素的innerHtml 与将发生的元素放置交换,而是交换outerHtml

var draggedItem = null;
var ul = document.getElementById('ms-saturday');

// delegate event handling to the parent of the list items
ul.addEventListener('dragstart', buffer(handleDragStart), false);
ul.addEventListener('dragover', buffer(handleDragOver), false);
ul.addEventListener('drop', buffer(handleDrop), false);

function handleDragStart(e) 
  draggedItem = e.target;
  e.dataTransfer.effectAllowed = 'move';

  // dataTransfer is not really required, but I think IE may need it.
  // Also, not that if you must use dataTransfer API,
  // IE strongly requires that the mime type must be 'text'.
  e.dataTransfer.setData('text', this.innerHTML);


function handleDragOver(e) 
  if (e.preventDefault) 
    e.preventDefault();
  

  e.dataTransfer.dropEffect = 'move';

  return false;


function handleDrop(e) 
  var tmp;

  if (e.stopPropagation) 
    e.stopPropagation();
  

  if (draggedItem !== e.target) 
    // swapp outerHtml here
    tmp = draggedItem.outerHTML;
    draggedItem.outerHTML = e.target.outerHTML;
    e.target.outerHTML = tmp;;
  

  return false;


// this is used to create the handlers so that there won't be
// a need to repeat 'if (e.target === ul) ...' for as many times
// as there are handlers needed.
function buffer(fn) 

  return function(e) 

    // ignore drag-and-drop on the parent element itself
    if (e.target === ul) 
      return;
    

    fn.call(this, e);
  ;

我让你根据自己的喜好改进这种方法。

【讨论】:

感谢您的帮助,非常感谢。

以上是关于HTML5 可拖动列表 - 多个 setData?的主要内容,如果未能解决你的问题,请参考以下文章

H5 拖拽,直接指对象设置可拖拽

HTML5:使可编辑的文本区域可拖动而没有副作用?

Android中包含多个可拖动列表的水平滚动

[html5] 学习笔记- html拖放

淘汰赛 - 元素变得不可拖动 - HTML5拖放

使用带拖放的dataTransfer.setData传输JSON