事件处理

    我们可以使用 v-on 指令 (通常缩写为 @ 符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click="methodName" 或使用快捷方式 @click="methodName"

    例如:

    1. Vue.createApp({
    2. data() {
    3. return {
    4. counter: 1
    5. }
    6. }
    7. }).mount('#basic-event')

    结果:

    事件处理方法

    然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。

    例如:

    1. <div id="event-with-method">
    2. <!-- `greet` 在下面定义的方法名 -->
    3. <button @click="greet">Greet</button>
    4. </div>
    1. Vue.createApp({
    2. data() {
    3. return {
    4. name: 'Vue.js'
    5. }
    6. },
    7. methods: {
    8. greet(event) {
    9. // `this` 内部 `methods` 指向当前活动实例
    10. alert('Hello ' + this.name + '!')
    11. // `event` 是原生 DOM event
    12. if (event) {
    13. alert(event.target.tagName)
    14. }
    15. }
    16. }).mount('#event-with-method')

    结果:

    除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:

    1. <div id="inline-handler">
    2. <button @click="say('hi')">Say hi</button>
    3. <button @click="say('what')">Say what</button>
    4. </div>

    结果:

    有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法:

    1. <button @click="warn('Form cannot be submitted yet.', $event)">
    2. Submit
    3. </button>
    1. methods: {
    2. warn(message, event) {
    3. // now we have access to the native event
    4. if (event) {
    5. event.preventDefault()
    6. }
    7. alert(message)
    8. }
    9. }

    多事件处理器

    事件处理程序中可以有多个方法,这些方法由逗号运算符分隔:

    1. <!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
    2. <button @click="one($event), two($event)">
    3. Submit
    4. </button>
    1. // ...
    2. methods: {
    3. one(event) {
    4. // first handler logic...
    5. },
    6. two(event) {
    7. // second handler logic...
    8. }
    9. }

    在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

    • .stop
    • .prevent
    • .capture
    • .self
    • .passive

    TIP

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

    1. <!-- 点击事件将只会触发一次 -->
    2. <a @click.once="doThis"></a>

    不像其它只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的上。如果你还没有阅读关于组件的文档,现在大可不必担心。

    Vue 还对应 addEventListener 中的 passive 选项 (opens new window)提供了 .passive 修饰符。

    1. <!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
    2. <!-- 而不会等待 `onScroll` 完成 -->
    3. <!-- 这其中包含 `event.preventDefault()` 的情况 -->
    4. <div @scroll.passive="onScroll">...</div>

    这个 修饰符尤其能够提升移动端的性能。

    TIP

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

    按键修饰符

    在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 或者 @ 在监听键盘事件时添加按键修饰符:

    1. <!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
    2. <input @keyup.enter="submit" />

    你可以直接将 暴露的任意有效按键名转换为 kebab-case 来作为修饰符。

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

    在上述示例中,处理函数只会在 $event.key 等于 'PageDown' 时被调用。

    Vue 为最常用的键提供了别名:

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

    提示

    注意:在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。

    例如:

    TIP

    请注意修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。

    .exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。

    1. <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
    2. <button @click.ctrl="onClick">A</button>
    3. <!-- 有且只有 Ctrl 被按下的时候才触发 -->
    4. <button @click.ctrl.exact="onCtrlClick">A</button>
    5. <!-- 没有任何系统修饰符被按下的时候才触发 -->
    6. <button @click.exact="onClick">A</button>
    • .left
    • .right
    • .middle

    这些修饰符会限制处理函数仅响应特定的鼠标按钮。

    为什么在 HTML 中监听事件?

    你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 或 @ 有几个好处:

    1. 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。

    2. 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。