带有 Computed 属性 的 Vue3 For-Loop 立即触发 onDragEnd

Vue3 For-Loop with Computed Property triggers onDragEnd immediately

我正在尝试为表单生成器开发我自己的简单拖放功能。我有一个项目列表,它在一个 v-for 循环中呈现,计算 属性。在 onDragStart 上,我设置了状态 isDragging。这应该会改变计算 属性 中的列表,并插入一些我可以放置拖动项的插槽。但是在拖动一个item之后,它立即触发了onDragEnd事件。

最初我缺少 :key 属性,但添加它并没有解决问题。希望有人知道解决方案或知道哪里出了问题。

这里是一个Link代码: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')

我认为问题在于选择使用 ondragstart 事件。当它被触发时, DOM 是 re-rendered 来显示你的插槽,它会四处移动,这样你的鼠标光标就不再位于元素本身上。 dragend 然后在拖动实际开始之前被触发。只需将其更改为 ondrag 即可:

https://jsfiddle.net/m7ps3f40/

为了调试和解决这个问题,我大大简化了您的 fiddle。我觉得 dragList 计算和 :bind="getProps" 使用了更多的代码,并且与仅使用 HTML 元素和 Vue-style 事件进行拖动的更简单方法相比,可读性更差。看看你可能会觉得很有趣:

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

当然,您的 fiddle 可能是一段较大代码的缩减版本,因此您可能需要坚持自己的方法。