首页 > 解决方案 > 以与 mousedown/mousemove/mouseup 相同的方式处理 touchstart/touchmove/touchend

问题描述

我正在尝试在我的应用程序中添加触摸和拖动功能,但到目前为止没有成功。

这是想法:

  1. 用户触摸一个元素来激活它
  2. 他将手指移过元素的兄弟姐妹以激活它们
  3. 如果他移开手指,所有元素都将停用

我可以使它与鼠标事件完美结合,但触摸事件的工作方式似乎有所不同。我认为这是因为一旦触发了 touchstart,其他触摸事件就会绑定到同一个初始目标。在这里磨我的齿轮的是,触摸端可以绑定到父元素并且可以工作......

这是一个示例代码。您可以看到它在鼠标事件中按预期工作,但如果您模拟触摸,它就不再工作了。

Vue.component('to-press', {
  template: `<span class="col-3 p-2 bg-light border" :class="{ 'bg-dark': isActive }" @mousedown="emitPanMode()"  @touchstart="emitPanMode()" @mousemove="setActive()" @touchmove="setActive()">&nbsp;</span>`,
  props: ['isPan'],
  data() {
    return {
      isActive: false,
    }
  },
  methods: {
    emitPanMode() {
      this.isActive = true;
      this.$emit('on-pan');
    },
    setActive() {
      this.isActive = this.isPan;
    }
  },
  watch: {
    isPan(val) {
      if (!val) {
        this.isActive = false;
      }
    }
  }
})

const app = new Vue({
  el: "#app",
  data() {
    return {
      panMode: false,
    };
  },
  methods: {
    togglePanMode(val) {
      this.panMode = val;
    }
  }
})
* {
  -webkit-touch-callout: none;
  /* iOS Safari */
  -webkit-user-select: none;
  /* Safari */
  -khtml-user-select: none;
  /* Konqueror HTML */
  -moz-user-select: none;
  /* Firefox */
  -ms-user-select: none;
  /* Internet Explorer/Edge */
  user-select: none;
  /* Non-prefixed version, currently
                                    supported by Chrome and Opera */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<div id="app" class="container py-4" @mouseup="togglePanMode(false)" @touchend="togglePanMode(false)">
  <div class="row">
    <to-press v-for="i of 12" :key="i" @on-pan="togglePanMode(true)" :is-pan="panMode" />
  </div>
  <p>Click/touch a rectangle, hold and drag accross</p>
</div>

关于如何以与鼠标相同的方式处理触摸的任何见解?有什么我想念的吗?

标签: javascriptvue.jsevent-handlingmouseeventtouch-event

解决方案


看来我们必须touchmove从父组件处理。

看这个例子

Vue.component('to-press', {
  template: `<span class="col-3 p-2 bg-light border" :class="{ 'bg-dark': isActive }" @mousedown="emitPanMode()"  @touchstart="emitPanMode()" @mousemove="setActive()" @touchmove="setActive()">&nbsp;</span>`,
  props: ['isPan'],
  data() {
    return {
      isActive: false,
    }
  },
  methods: {
    emitPanMode() {
      this.isActive = true;
      this.$emit('on-pan');
    },
    setActive() {
    	this.isActive = this.isPan;
    }
  },
  watch: {
    isPan(val) {
      if (!val) {
        this.isActive = false;
      }
    }
  }
})

const app = new Vue({
  el: "#app",
  data() {
    return {
      panMode: false,
    };
  },
  methods: {
    togglePanMode(val) {
      this.panMode = val;
    },
    move(e) {
      let p = e.touches[0];
      let el = document.elementFromPoint(p.clientX, p.clientY);
      let cmp = this.$children.find(c => c.$el === el);
      if (cmp) {
        cmp.setActive()
      }
    }
  }
})
* {
  -webkit-touch-callout: none;
  
  /* iOS Safari */
  -webkit-user-select: none;
  
  /* Safari */
  -khtml-user-select: none;
  
  /* Konqueror HTML */
  -moz-user-select: none;
  
  /* Firefox */
  -ms-user-select: none;
  
  /* Internet Explorer/Edge */
  user-select: none;
  
  /* Non-prefixed version, currently supported by Chrome and Opera */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<div id="app" class="container py-4" @mouseup="togglePanMode(false)" @touchend="togglePanMode(false)" @touchmove.passive="move">
  <div class="row">
    <to-press v-for="i of 12" :key="i" @on-pan="togglePanMode(true)" :is-pan="panMode" />
  </div>
  <p>Click/touch a rectangle, hold and drag accross</p>
</div>


推荐阅读