3

以下に示すように、ドラッグ可能liな要素が aulにネストされ、次に a にネストされていdivます。

  <div class='group'>
    <div class='header'>
    // some stuff here
    </div>
    <ul>
      <li draggable='true'> 
         Stuff I want to drag and drop to another div.group
      </li>
    </ul>
  </div>

これらのdiv要素は複数あり、ドラッグ アンド ドロップ機能を実装して、あるグループのli要素divを別のグループに移動しようとしています。

ondragenterここに,コールバックを接続しましたondragleave:

 // controller using mithril.js
    ctrl.onDragLeave = function () {
        return function (event) {
            var target;
            // Using isDropzone to recursively search for the appropriate div.group 
            // parent element, as event.target is always the children inside it
            if ((target = isDropzone(event.target)) != null) {
                target.style.background = "";
            }
        }
    };
    ctrl.onDragEnter = function () {
        return function (event) {
            var target;
            if ((target = isDropzone(event.target)) != null) {
                target.style.background = "purple";
            }
        };
    };
    function isDropzone(elem){
        if(elem == null){
            return null;
        }
        return elem.className == 'group' ? elem: isDropzone(elem.parentNode)
    }

問題は、コールバックの が常になどevent.targetの 内のネストされた子要素であり、したがってコールバックが常に起動される場合に発生します。この場合、コールバックでの色を変更しているため、望ましくない点滅が発生します。divlidiv.groupdiv.group

イベントを委任し、div祖父母のみがliイベントを処理できるようにする方法はありますか? または、これを回避する他の方法はありますか?

編集:これを行う方法があるかどうかを知りたいのですが、現在、私はここで見つけた回避策を使用しています。

4

1 に答える 1

0

したがって、これは「別の角度からアプローチする必要がある」カテゴリの回答に当てはまります。

アタッチされたハンドラーで event.target/event.currentTarget から DOM を操作することは、できるだけ避けてください。

いくつかの点が異なります:

  1. あなたondragleaveondragenterハンドラーは、コントローラー/ビューモデル/ストアに適切な「状態」属性を設定するだけです

  2. ハンドラーが解決されると、通常、Mithril で再描画がトリガーされます。内部m.startComputation()で開始し、ハンドラーが呼び出されてからm.endComputation()

  3. 「表示機能」が再び実行されます。その後、変更されたモデルが反映されます。アクションはビューを変更せず、ビューはモデルに影響を与えるアクションを呼び出し、それらの変更に反応します。MVVMではなくMVC


モデル

コントローラーで、ドラッグ アンド ドロップ UI を表示するために必要なすべての状態を追跡するモデルをセットアップします。

ctrl.dragging = m.prop(null)

ctrl.groups = m.prop([
  {
    name: 'Group A',
    dragOver: false,
    items: ['Draggable One', 'Draggable Two']
  },
  ...
  // same structure for all groups
])

意見

ビューで、モデルの状態を反映する UI を設定します。アクションに関する十分な情報をコントローラーに渡すイベントハンドラーを用意します。アクションに適切に応答し、それに応じてモデルを操作するのに十分です。


return ctrl.groups.map(function (group, groupIdx) {
  return m('.group',[
    m('.header', group.name),
    m('ul', 
      {
        style: { background: (group.dragOver ? 'blue' : '')},
        ondragleave: function () {ctrl.handleDragLeave(groupIdx)},
        ondragenter: function () {ctrl.handleDragEnter(groupIdx)},
        ondrop: function () {ctrl.handleDrop(groupIdx)},
        ondragover: function (e) {e.preventDefault()}
      },
      group.items.map(function (item, itemIdx) {
        return m('li',
          {
            draggable: true,
            ondragstart: function () {ctrl.handleDragStart(itemIdx, groupIdx)}
          },
          item
      })
    )
  ])
})

これで、コントローラーの状態/モデルの変更に反応してグループが適切に表示されるように設定されました。グループに新しいアイテムがあるとか、グループに新しい背景色が必要とか、何かを伝えるために dom を操作する必要はありません。コントローラーがモデルを操作できるようにイベント ハンドラーをアタッチするだけで、そのモデルに基づいてビューが再描画されます。

コントローラ

したがって、コントローラーには、モデルの更新に必要なアクションからのすべての情報を持つハンドラーを含めることができます。

コントローラーの一部のハンドラーは次のようになります。

ctrl.handleDragStart = function (itemIdx, groupIdx) {
  ctrl.dragging({itemIdx: itemIdx, groupIdx: groupIdx})
}

ctrl.handleDragEnter = function (groupIdx) {
  ctrl.groups()[groupIdx].dragOver = true
}

ctrl.handleDragLeave = function (groupIdx) {
  ctrl.groups()[groupIdx].dragOver = false
}

ctrl.handleDrop = function (toGroupIdx) {
  var groupIdx = ctrl.dragging().groupIdx
  var itemIdx = ctrl.dragging().itemIdx
  var dropped = ctrl.groups()[groupIdx].items.splice(itemIdx, 1)[0]

  ctrl.groups()[toGroupIdx].items.push(dropped)
  ctrl.groups()[toGroupIdx].dragOver = false
  ctrl.dragging(null)
}

Mithril の MVC モデル イベント ハンドラーは、モデルを操作するコントローラーでアクションを呼び出すようにしてください。その後、ビューはそれらのモデルの変更に反応します。これにより、DOM イベントの詳細に巻き込まれる必要がなくなります。

これは、取得しようとしているものを示す完全な JSbin の例です。

https://jsbin.com/pabehuj/edit?js,console,output

イベントの委任についてまったく心配する必要なく、目的の効果が得られます。

また、JSbin のondragenterハンドラーで次の点に注意してください。

ondragenter: function () {
  if (ctrl.dragging().groupIdx !== groupIdx) {
    ctrl.handleDragEnter(groupIdx)
  }
}

これは、ドロップ可能な領域がそれ自体のドラッグ可能で色が変わらないようにするためです。これは、回答で探していると思うものの1つです。

于 2016-09-30T14:54:08.253 に答える