Home > front end >  Vue3 For-Loop with Computed Property triggers onDragEnd immediately
Vue3 For-Loop with Computed Property triggers onDragEnd immediately

Time:05-02

I am trying do develop my own simple drag and drop functionality for a form builder. I have got a list of items which is rendered in a v-for loop with a computed property. On onDragStart I set the state isDragging. This should alter the list in the computed property and insert some slots where I can drop the dragged item. But immediatly after dragging an item, it triggers the onDragEnd Event.

Initialy i was missing the :key property, but adding it didnt solve the problem. Hopefully someone knows a solution or has an idea whats wrong.

Here is a Link to the code: https://jsfiddle.net/elrihor/vwb3k6qc/49/

Vue.createApp({
  data() {
    return {
      list: [{
          id: 'i1',
          name: 'Apfel',
        },
        {
          id: 'i2',
          name: 'Banane',
        },
        {
          id: 'i3',
          name: 'Kirsche',
        },
        {
          id: 'i4',
          name: 'Orange',
        },
      ],
      props: {
        item: {
          props: {
            draggable: true,
            ondragstart: ($event) => {
              this.startDrag();
            },
            ondragend: ($event) => {
              this.endDrag();
            },
          },
        },
        slot: {
          props: {
            ondrop: ($event) => {
                $event.preventDefault();
              this.onDrop($event);
            },
            ondragover: ($event) => {
                $event.preventDefault();
            }
          },
        },
      },
      isDragging: false
    }
  },
  computed: {
    dragList() {
      let dragList = this.list;

      if (this.isDragging) {
        dragList = dragList.reduce((r, a) => r.concat(a, {
          type: 'slot',
          name: 'Slot'
        }), [{
          type: 'slot',
          name: 'Slot'
        }]);
      }

      dragList = dragList.map((item, index) => {
        return {
          ...item,
          id: !item.id ? 's'   index : item.id,
          type: item.type == 'slot' ? 'slot' : 'item',
        };
      });

      return dragList;
    }
  },
  methods: {
    getProps(type) {
      return this.props[type].props;
    },
    startDrag() {
      console.log('start');
      this.isDragging = true;
    },
    endDrag() {
      console.log('end');
      this.isDragging = false;
    },
    onDrop(e) {
      console.log('drop');
    }
  }
}).mount('#app')

CodePudding user response:

I think the issue lies in choosing to use the ondragstart event. When this is fired, the DOM is re-rendered to display your slots, which moves things around so that your mouse cursor is no longer over the element itself. dragend is then fired before the drag actually commenced. Change this simply to ondrag and it will work:

https://jsfiddle.net/m7ps3f40/

To debug and figure this out, I simplified your fiddle a lot. I felt the dragList computed and the :bind="getProps" used more code and is less readable than the a simpler approach of just using HTML elements and Vue-style events for dragging. You might find it interesting to take a look:

https://jsfiddle.net/o5pyhtd3/2/

but of course your fiddle might be a cut down version of a bigger piece of code, so perhaps you need to stick to your approach.

  • Related