简体   繁体   中英

How to keep dragging item at former position until release in vue draggable

I'm implementing a nested layers component in vue with vuedraggable. I try to keep it close to Adobe's layers panel (for example in Illustrator).

The desired behaviour is: While dragging an item, it remains at it's position and only a black line is indicating where the item would be inserted after releasing the drag.

The black line could be realised by styling vue draggable's ghost. But how can I prevent the item from being removed from its original position while dragging?

Adobe Illustrator layers example

So I ended up using sl-vue-tree which does basically everything I need to simulate Adobe Illustrators layer panel.

In essence, create a copy of the item on click, then set the selected item to invisible. On mouse-up, hide the copy and make the item visible again.

An example:

ball.onmousedown = function(event) { // (1) start the process

  // (2) prepare to moving: make absolute and on top by z-index

  var ball2 = ball; //set the balls current position so it doesn't appear to move
  ball.style.position = 'absolute';
  ball.style.visibility = "hidden"; //make the moving item invisible

  document.body.append(ball);
  // ...and put that absolutely positioned ball under the pointer

  moveAt(event.pageX, event.pageY);

  // centers the ball at (pageX, pageY) coordinates
  function moveAt(pageX, pageY) {
    ball.style.left = pageX - ball.offsetWidth / 2 + 'px';
    ball.style.top = pageY - ball.offsetHeight / 2 + 'px';

  }

  function onMouseMove(event) {
    moveAt(event.pageX, event.pageY);
  }

  // (3) move the ball on mousemove
  document.addEventListener('mousemove', onMouseMove);

  // (4) drop the ball, remove unneeded handlers
  ball.onmouseup = function() {
    ball.style.visibility = "visible"; //makes the moved ball visible again
    ball2.style.visibility = "hidden"; //makes the copy invisible
    document.removeEventListener('mousemove', onMouseMove);
    ball.onmouseup = null;
  };

};

I now use a similar approach to Death Waltz's answer , but without manipulating the DOM directly.

Instead I make a copy of the item in the list...

start(event) {
    // Make a clone of the choosen item and add it to the
    // layers list.
    const index = event.oldIndex
    const item = this.layers[index]
    this.layers.splice(index + 1, 0, {
    ...item,
    // Vue requires unique keys.
    id: item.id + '_clone',
    // Set a isClone flag to be able to delete the clone
    // afterwards.
    isClone: true
  })
},

...and delete it afterwards

end() {
    // Delete the clone from the layers.
    this.layers = this.layers.filter(layer => !layer.isClone)
}

here is the full example: https://jsfiddle.net/arnoson/587L0nx9/45/

I'm still not sure if this is the most elegant solution and wish there would be a built in way to do this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM