事件监听

在vue模版语法中我们可以用v-on或者它的缩写@来监听DOM事件,比如v-on:click="count++"@click="countMethod()"(无参括号可省略)

事件处理方法

一般事件的处理逻辑都比较复杂,所以像上面那样直接把js写在指令中是不行的,这时我们就需要结合组件的方法来使用了。我们可以把我们的逻辑写在定义的方法中,然后在指令中调用即可。

<button @click="change">change</button>
<button @click="change2('this is input param')">change2</button>
<button @click="change2">change2</button>
<button @click="change3(1)">change3</button>
<button @click="change3(1, $event)">change3</button>

<!-- 同时处理多事件时可以用逗号隔开,但函数括号不能省略,event参数也需要显式传入 -->
<button @click="change(), change2('hello'), change3(1, $event)">changeALL</button>

<script>
export default {
  name: "Demo",
  methods: {
    change() {
      console.log('method has used.');
      this.tips = this.tips + ' by change.'
    },
    change2(e) {
      console.log('-----------default $event param-----------');
      // 如果传参数,e会是传的值;如果不显式传参,则默认e为Vue封装的DOM事件对象(此时函数调用时括号必须省略才行)
      console.log(e);
    },
    change3(i, e) {
      console.log('-----------$event param-----------');
      // 两个参数以上时e必须显式传入$event参数才能获取到DOM事件对象
      console.log(e);
    }
  }
}
</script>

事件修饰符

事件修饰符就是为v-on指令(缩写@)用.开头的指令后缀,比如@click.once只点击一次。

vue提供的事件修饰符总共有这些:

  • stop(阻止事件冒泡)
  • .prevent(阻止默认事件)
  • .capture(添加事件监听器,使用事件捕获模式,即可以将传播过来的事件优先处理)
  • .self(只有事件在元素本身触发时才触发,即不是通过内部元素触发的)
  • .once(事件只触发一次)
  • .passive(滚动事件的默认行为 (即滚动行为) 将会立即触发,这个修饰符对应addEventListener中的passive选项)

下面是一个简单的冒泡事件案例

<template>
  <div @click="log('click the big box.'),log('---------------分割线---------------')" style="background-color: pink; width: 300px; height: 300px;">
    <div @click="log('click the middle box.')" style="background-color: orange; width: 200px; height: 200px;">
      <div @click="log('click the small box.')"
           style="background-color: skyblue; width: 100px; height: 100px;"></div>
    </div>
  </div>
</template>

<script>
export default {
  name: "bubble",
  methods: {
    log(tip) {
      console.log(tip);
    }
  }
}
</script>

如果要处理冒泡事件,可以使用Vue提供的几个修饰符,比如:stopself

<!-- 使用stop修饰符处理,阻止事件继续传播 -->
<template>
  <div @click="log('click the big box.')" style="background-color: pink; width: 300px; height: 300px;">
    <div @click.stop="log('click the middle box.'),log('---------------分割线---------------')" style="background-color: orange; width: 200px; height: 200px;">
      <div @click.stop="log('click the small box.'),log('---------------分割线---------------')"
           style="background-color: skyblue; width: 100px; height: 100px;"></div>
    </div>
  </div>
</template>

<script>
export default {
  name: "bubble",
  methods: {
    log(tip) {
      console.log(tip);
    }
  }
}
</script>
<!-- 使用self修饰符处理,点击到当前盒子才会触发事件 -->
<template>
  <div @click.self="log('click the big box.')" style="background-color: pink; width: 300px; height: 300px;">
    <div @click.self="log('click the middle box.'),log('---------------分割线---------------')" style="background-color: orange; width: 200px; height: 200px;">
      <div @click="log('click the small box.'),log('---------------分割线---------------')"
           style="background-color: skyblue; width: 100px; height: 100px;"></div>
    </div>
  </div>
</template>

<script>
export default {
  name: "bubble",
  methods: {
    log(tip) {
      console.log(tip);
    }
  }
}
</script>
<!-- 使用stop、self结合处理 -->
<template>
  <div @click="log('click the big box.')" style="background-color: pink; width: 300px; height: 300px;">
    <div @click.self.stop="log('click the middle box.'),log('---------------分割线---------------')" style="background-color: orange; width: 200px; height: 200px;">
      <div @click="log('click the small box.'),log('---------------分割线---------------')"
           style="background-color: skyblue; width: 100px; height: 100px;"></div>
    </div>
  </div>
</template>

<script>
export default {
  name: "bubble",
  methods: {
    log(tip) {
      console.log(tip);
    }
  }
}
</script>

可以通过.capture调整传播事件的处理顺序:

<template>
  <div @click.capture="log('click the big box.'),log('---------------分割线---------------')" style="background-color: pink; width: 300px; height: 300px;">
    <div @click.self.stop="log('click the middle box.')" style="background-color: orange; width: 200px; height: 200px;">
      <div @click="log('click the small box.')"
           style="background-color: skyblue; width: 100px; height: 100px;"></div>
    </div>
  </div>
</template>

<script>
export default {
  name: "bubble",
  methods: {
    log(tip) {
      console.log(tip);
    }
  }
}
</script>

阻止元素默认事件的修饰符.prevent

<!-- 这样form的提交功能就失效了 -->
<form @submit.prevent></form>

不要把.passive.prevent一起使用,因为.prevent将会被忽略,同时浏览器可能会向你展示一个警告。请记住.passive会告诉浏览器你不想阻止事件的默认行为。

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用v-on:click.prevent.self会阻止所有的点击,而v-on:click.self.prevent只会阻止对元素自身的点击。

按键修饰符

区别于事件修饰符,按键修饰符顾名思义就是修改用户按下键盘上的按键时触发的操作,Vue为我们提供了可以直接将KeyboardEvent.key暴露的任意有效按键名转换为kebab-case来作为修饰符。

<input @keyup.page-down="onPageDown" />
<input @keyup.enter="submit"/>

另外Vue还为常用的按键提供了别名:

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

系统修饰键

也就是我们常用的Ctrl(或)、Alt(或)、Shiftmeta键(Win键或者),这些键配合其他键时都是长按才会生效而非按一次即可,Vue为我们提供的修饰符是:

  • .ctrl
  • .alt
  • .shift
  • .meta
<input @keyup.ctrl.b="log(click the Ctrl + B)"/>

上面的可以用Ctrl + B触发也可以用Ctrl + Shift + B等触发,如果想要精准触发则可以使用.exact修饰符控制。

!-- 在 Ctrl 被按下的时候,即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>

鼠标修饰符

下面这三个可以用来控制鼠标的操作监听。

  • .left
  • .right
  • .middle
<button @click.prevent.right.exact="log('鼠标右键点击.')">点击</button>