vue.js 拖放事件触发多次

jv2fixgn  于 2023-03-09  发布在  Vue.js
关注(0)|答案(1)|浏览(255)

我正在开发一个带有拖放功能的Web应用程序。到目前为止,我使用的是基本的HTML5拖动功能,但现在我切换到使用interact.js库。
我不知道我的问题是特定于这个库还是更一般的问题:拖放时的事件通常会触发多次(如果我没有看错的话,它似乎总是正好4次,但不能保证)。
我也使用Vue.js,这是我的代码:

<template>
    <v-card
      elevation="0"
      :id="id"
      class="board device-dropzone"
    >
        <slot class="row"/>
        <div
         Drop Card here
        </div>
    </v-card>
</template>

在槽中,添加了一个图像和带有文本的div。

<script>
import interact from 'interactjs';

export default {
  name: 'Devices',
  props: ['id', 'acceptsDrop'],
  data() {
    return {
      extendedHover: false,
      hoverEnter: false,
      timer: null,
      totalTime: 2,
    };
  },
  methods: {
    resetHover() {
      alert('reset');
    },
    drop(e) {
      let wantedId = e.relatedTarget.id.split('-')[0];
      console.log(wantedId);
      console.warn(e.target);
      e.target.classList.remove('hover-drag-over');
      this.extendedHover = false;
      console.log('-------------dropped');
      console.warn('dropped onto device');
      this.$emit('dropped-component', cardId);
      e.target.classList.remove('hover-drag-over'); */
    },
    dragenter() {
      console.log('------------dragenter');
      this.hoverEnter = true;
        setTimeout(() => {
          this.extendedHover = true;
          console.log('extended hover detected');
        }, 2000);
      } */
      this.timerID = setTimeout(this.countdown, 3000);
    },
    dragover(e) {
      if (this.acceptsDrop) {
        e.target.classList.add('hover-drag-over');
      }
    },
    dragleave(e) {
      if (this.acceptsDrop) {
        clearInterval(this.timer);
        this.timer = null;
        this.totalTime = 2;
        e.target.classList.remove('hover-drag-over');
        this.extendedHover = false;
        this.hoverEnter = false;
        console.log('................');
        console.warn(this.extendedHover);
        // this.$emit('cancel-hover');
      }
    },
    countdown() {
     console.log('!!!!!!!!!!!!!!!!!!!!');
     if (this.hoverEnter === true) {
        this.extendedHover = true;
        console.log('-------------------');
        console.warn(this);
        console.warn(this.extendedHover);
        this.$emit('long-hover');
      } 
    },
  },
  mounted() {
    // enable draggables to be dropped into this
    const dropzone = this;
    interact('.device-dropzone').dropzone({
      overlap: 0.9,
      ondragenter: dropzone.dragenter(),
      ondrop: function (event) {
        dropzone.drop(event);
      },
    })
  },
};
</script>

可拖动组件如下所示:

<template>
  <v-card
    class="primary draggable-card"
    :id = "id"
    :draggable = "false"
    @dragover.stop
    ref="interactElement"
  >
    <slot/>
  </v-card>

使用脚本:

<script>
import interact from 'interactjs';

export default {
  props: ['id', 'draggable'],
  data() {
    return {
      isInteractAnimating: true,
      position: { x: 0, y: 0 },
    };
  },
  methods: {
    /* dragStart: (e) => {
      e.stopPropagation(); // so dragStart of ParentBoard does not get triggered as well
      // eslint-disable-next-line
      const target = e.target;
      e.dataTransfer.setData('card_id', target.id);
      e.dataTransfer.setData('type', 'widget');
      // for some delay
      setTimeout(() => {
        console.log('started dragging');
      }, 0);
    }, */
    dragEndListener: (event) => {
      console.warn('+++++++++++++++++++++++++++');
      // console.warn(event.currentTarget.id);
      if (document.getElementById(event.currentTarget.id)) {
        event.currentTarget.parentNode.removeChild(event.currentTarget);
      }
    },
    dragMoveListener: (event) => {
      /* eslint-disable */
      var target = event.target;
      // keep the dragged position in the data-x/data-y attributes
      const xCurrent = parseFloat(target.getAttribute('data-x')) || 0;
      const yCurrent = parseFloat(target.getAttribute('data-y')) || 0;
      const valX = xCurrent + event.dx;
      const valY = yCurrent + event.dy;
      // translate the element
      event.target.style.transform =
        `translate(${valX}px, ${valY}px)`

      // update the postion attributes
      target.setAttribute('data-x', x);
      target.setAttribute('data-y', y);
    }
    /* eslint-enable */
  },
  mounted() {
    const element = this.$refs.interactElement;
    console.log(element);
    // interact(element).draggable({
    const component = this;
  interact('.draggable-card')
    .draggable({ 
      manualStart: true,
      onmove: component.dragMoveListener,
      onend:component.dragEndListener,
    })
    .on('move', function (event) {
      var interaction = event.interaction;
      // if the pointer was moved while being held down
      // and an interaction hasn't started yet
      if (interaction.pointerIsDown && !interaction.interacting()) {
        var original = event.currentTarget;
        // create a clone of the currentTarget element
        const clone = event.currentTarget.cloneNode(true);
        clone.id = clone.id + "-clone"; 
        clone.classname += " dragged-clone";
        // insert the clone to the page
        document.body.appendChild(clone);

        clone.style.opacity = 0.5;

        // start a drag interaction targeting the clone
        interaction.start({ name: 'drag' },
          event.interactable,
          clone);
      } 
    })
    .on('end', function (event) {
      console.error('end drag');
    });
  },
  /* eslint-enable */
};
</script>

一般来说,拖放是可以的。但是我不明白为什么,例如,当只拖放一张卡片时,拖放事件会触发四次。有人能帮我吗?

vmdwslir

vmdwslir1#

我在使用相同的框架和库时也遇到了类似的问题。由于有一些基于事件触发的逻辑,所以当它多次触发时,它正在破坏我的应用程序。
我怀疑该问题与bubbling of events有关。
因此,在我的例子中,解决方案是在drop(event)处理程序中添加event.stopImmediatePropagation()
正如参考文章中提到的,在停止事件冒泡时应该注意不要在其他地方产生不可预见的后果。

相关问题