简体   繁体   English

vue.js:如何处理同一元素上的 click 和 dblclick 事件

[英]vue.js: how to handle click and dblclick events on same element

I have a vue component with separate events for click/dblclick.我有一个带有单独事件的 vue 组件,用于单击/dblclick。 Single click (de)selects row, dblclick opens edit form.单击(取消)选择行,dblclick 打开编辑表单。

<ul class="data_row"
  v-for="(row,index) in gridData"
  @dblclick="showEditForm(row,$event)"
  @click="rowSelect(row,$event)"
>

Doing it like this, i get 3 events fired on double click.这样做,我会在双击时触发 3 个事件。 Two click events and lastly one dblclick.两个点击事件和最后一个 dblclick。 Since the click event fires first , is there a way (short of deferring click event for a fixed amount of ms) for stopping propagation of click event on double click ?由于点击事件首先触发,有没有办法(没有将点击事件延迟固定数量的毫秒)来停止双击点击事件的传播?

Fiddle here在这里摆弄

As suggested in comments, You can simulate the dblclick event by setting up a timer for a certain period of time(say x).正如评论中所建议的,您可以通过设置一段时间(例如 x)的计时器来模拟 dblclick 事件。

  • If we do not get another click during that time span, go for the single_click_function().如果我们在这段时间内没有再次点击,请使用 single_click_function()。
  • If we do get one, call double_click_function().如果我们得到一个,调用 double_click_function()。
  • Timer will be cleared once the second click is received.一旦收到第二次点击,计时器将被清除。
  • It will also be cleared once x milliseconds are lapsed.一旦 x 毫秒过去,它也会被清除。

See below code and working fiddle .请参阅下面的代码和工作小提琴

new Vue({
    el: '#app',
    data: {
        result: [],
        delay: 700,
        clicks: 0,
        timer: null
    },    
     mounted: function() {
        console.log('mounted');
     },      
     methods: {
        oneClick(event) {
          this.clicks++;
          if (this.clicks === 1) {
            this.timer = setTimeout( () => {
              this.result.push(event.type);
              this.clicks = 0
            }, this.delay);
          } else {
             clearTimeout(this.timer);  
             this.result.push('dblclick');
             this.clicks = 0;
          }         
        }      
     }
});
<div id="example-1">
 <button v-on:dblclick="counter += 1, funcao()">Add 1</button>
   <p>The button above has been clicked {{ counter }} times.</p>
</div>
var example1 = new Vue({
 el: '#example-1',
 data: {
   counter: 0
 },
 methods: {
   funcao: function(){
     alert("Sou uma funcao");
   }
 }
})

check out this working fiddle https://codepen.io/robertourias/pen/LxVNZX看看这个工作小提琴https://codepen.io/robertourias/pen/LxVNZX

i have a simpler solution i think (i'm using vue-class but same principle apply):我认为我有一个更简单的解决方案(我使用的是 vue-class 但适用相同的原则):

private timeoutId = null;
onClick() {
        if(!this.timeoutId)
        {
            this.timeoutId = setTimeout(() => {
                // simple click
            }, 50);//tolerance in ms
        }else{
            clearTimeout(this.timeoutId);
            // double click
        }
    }

it does not need to count the number of clicks.它不需要计算点击次数。

The time must be short between click and click.单击和单击之间的时间必须很短。

In order to get the click and double click, only one counter is required to carry the number of clicks(for example 0.2s) and it is enough to trap the user's intention when he clicks slowly or when he performs several that would be the case of the double click or default case.为了获得点击和双击,只需要一个计数器来承载点击次数(例如0.2s),当用户点击缓慢或执行多次时就足以捕获用户的意图。双击或默认情况。

I leave here with code how I implement these features.我将如何实现这些功能的代码留在这里。

 new Vue({ el: '#app', data: {numClicks:0, msg:''}, methods: { // detect click event detectClick: function() { this.numClicks++; if (this.numClicks === 1) { // the first click in .2s var self = this; setTimeout(function() { switch(self.numClicks) { // check the event type case 1: self.msg = 'One click'; break; default: self.msg = 'Double click'; } self.numClicks = 0; // reset the first click }, 200); // wait 0.2s } // if } // detectClick function } });
 span { color: red }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js"></script> <div id='app'> <button @click='detectClick'> Test Click Event, num clicks <span>{{ numClicks }}</span> </button> <h2>Last Event: <span>{{ msg }}</span></h2> </div>

I use this approach for the same problem.我使用这种方法解决同样的问题。 I use a promise that is resolved either by the timeout of 200ms being triggered, or by a second click being detected.我使用了一个通过触发 200 毫秒超时或检测到第二次点击来解决的承诺。 It works quite well in my recent web apps.它在我最近的网络应用程序中运行良好。

<div id="app">
  <div 
    @click="clicked().then((text) => {clickType = text})">
      {{clickType}}
  </div>
</div>

<script>
new Vue({
  el: "#app",
  data: {
    click: undefined,
    clickType: 'Click or Doubleclick ME'
  },
  methods: {
    clicked () {
      return new Promise ((resolve, reject) => {
        if (this.click) {
          clearTimeout(this.click)
          resolve('Detected DoubleClick')
        }
        this.click = setTimeout(() => {
         this.click = undefined
         resolve('Detected SingleClick')
        }, 200)
      })
    }
  }
})
</script>

Working fiddle: https://jsfiddle.net/MapletoneMartin/9m62Lrwf/工作小提琴: https : //jsfiddle.net/MapletoneMartin/9m62Lrwf/

vue Component组件

// html 
 <div class="grid-content">
    <el-button 
   @click.native="singleClick" 
   @dblclick.native="doubleClick" 
   class="inline-cell">
    click&dbclickOnSameElement</el-button>
 </div>
// script
<script>
let time = null;  // define time be null 
export default {
  name: 'testComponent',
  data() {
    return {
       test:''
    };
  },
  methods: {

   singleClick() {
     // first clear  time
      clearTimeout(time);
      time = setTimeout(() => {
        console.log('single click ing')
      }, 300); 
    },
  
   doubleClick() {
      clearTimeout(time);  
      console.log('double click ing');
    }
  }
}
</script>
selectedFolder = ''; // string of currently selected item
folderSelected = false; // preview selected item

selectFolder(folder) {
    if (this.selectedFolder == folder) {
        // double click
      this.folderSelected = false;
      this.$store.dispatch('get_data_for_this_folder', folder);
    } else {
      // single click
      this.selectedFolder = folder;
      this.folderSelected = true;
    }
},

@click.stop handles a single click and @dblclick.stop handles double click @click.stop处理单击, @dblclick.stop处理双击

<v-btn :ripple="false"
            class="ma-0"
            @click.stop="$emit('editCompleteGrvEvent', props.item)"
            @dblclick.stop="$emit('sendCompleteGrvEvent',props.item)">
    <v-icon>send</v-icon>
    </v-btn>

Unless you need to do expensive operations on single select, you can rework rowSelect into a toggle.除非您需要对单个选择执行昂贵的操作,否则您可以将 rowSelect 改造成切换。 Setting a simple array is going to be a lot faster, reliable, and more straightforward compared to setting up and canceling timers.与设置和取消计时器相比,设置一个简单的数组会更快、更可靠、更直接。 It won't matter much if the click event fires twice, but you can easily handle that in the edit function.如果单击事件触发两次并不重要,但您可以在编辑功能中轻松处理。

<template>
  <ul>
    <li :key="index" v-for="(item, index) in items">
      <a
        :class="{ 'active-class': selected.indexOf(item) !== -1 }"
        @click="toggleSelect(item)"
        @dblclick="editItem(item)"
      >
        {{ item.title }}
      </a>
      <!-- Or use a checkbox with v-model
      <label @dblclick="editItem(item)">
        <input type="checkbox" :value="item.id" v-model.lazy="selected" />
        {{ item.title }}
      </label>
      -->
    </li>
  </ul>
</template>

<script>
export default {
  data: function () {
    return {
      items: [
        {
          id: 1,
          title: "Item 1",
        },
        {
          id: 2,
          title: "Item 2",
        },
        {
          id: 3,
          title: "Item 3",
        },
      ],
      selected: [],
    };
  },

  methods: {
    editItem(item) {
      /*
       * Optionally put the item in selected
       * A few examples, pick one that works for you:
       */

      // this.toggleSelect(item); // If the item was selected before dblclick, it will still be selected. If it was unselected, it will still be unselected.

      // this.selected = []; // Unselect everything.

      // Make sure this item is selected:
      // let index = this.selected.indexOf(item.id);
      // if (index === -1) {
      //   this.selected.push(item.id);
      // }

      // Make sure this item is unselected:
      // let index = this.selected.indexOf(item.id);
      // if (index !== -1) {
      //   this.selected.splice(index, 1);
      // }

      this.doTheThingThatOpensTheEditorHere(item);
    },

    toggleSelect(item) {
      let index = this.selected.indexOf(item.id);
      index === -1
        ? this.selected.push(item.id)
        : this.selected.splice(index, 1);
    },

    // For fun, get an array of items that are selected:
    getSelected() {
      return this.items.filter((item) => this.selected.indexOf(item.id) !== -1);
    },
  },
};
</script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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