← 返回主页

第5课: 事件处理

监听事件

使用v-on指令(简写为@)监听DOM事件。

<template>
  <div>
    <!-- 完整语法 -->
    <button v-on:click="count++">点击次数: {{ count }}</button>

    <!-- 简写语法 -->
    <button @click="count++">点击次数: {{ count }}</button>

    <!-- 调用方法 -->
    <button @click="handleClick">点击我</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)

function handleClick() {
  console.log('按钮被点击了')
  count.value++
}
</script>

内联事件处理器

<template>
  <div>
    <button @click="count++">增加</button>
    <button @click="count--">减少</button>
    <button @click="say('hello')">打招呼</button>
    <p>计数: {{ count }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)

function say(message) {
  alert(message)
}
</script>

访问事件对象

<template>
  <div>
    <!-- 自动传入event -->
    <button @click="handleClick">点击1</button>

    <!-- 使用$event传入event -->
    <button @click="handleClickWithArg('hello', $event)">点击2</button>

    <!-- 箭头函数 -->
    <button @click="(event) => handleEvent(event)">点击3</button>
  </div>
</template>

<script setup>
function handleClick(event) {
  console.log(event.target.tagName)
}

function handleClickWithArg(message, event) {
  console.log(message, event.target)
}

function handleEvent(event) {
  console.log(event)
}
</script>

事件修饰符

<template>
  <div>
    <!-- 阻止默认行为 -->
    <form @submit.prevent="onSubmit">
      <button type="submit">提交</button>
    </form>

    <!-- 阻止事件冒泡 -->
    <div @click="divClick">
      <button @click.stop="buttonClick">点击</button>
    </div>

    <!-- 捕获模式 -->
    <div @click.capture="handleCapture">
      <button>捕获</button>
    </div>

    <!-- 只触发一次 -->
    <button @click.once="handleOnce">只触发一次</button>

    <!-- 只当事件在该元素本身触发时才触发回调 -->
    <div @click.self="handleSelf">
      <button>点击</button>
    </div>

    <!-- 修饰符可以链式调用 -->
    <form @submit.prevent.stop="onSubmit"></form>
  </div>
</template>

<script setup>
function onSubmit() {
  console.log('表单提交')
}

function divClick() {
  console.log('div被点击')
}

function buttonClick() {
  console.log('button被点击')
}

function handleCapture() {
  console.log('捕获阶段')
}

function handleOnce() {
  console.log('只执行一次')
}

function handleSelf() {
  console.log('self触发')
}
</script>
事件修饰符:
- .stop: 阻止事件冒泡
- .prevent: 阻止默认行为
- .capture: 使用捕获模式
- .self: 只在元素本身触发
- .once: 只触发一次
- .passive: 提升移动端性能

按键修饰符

<template>
  <div>
    <!-- 按下Enter键 -->
    <input @keyup.enter="submit" placeholder="按Enter提交">

    <!-- 按下Delete或Backspace键 -->
    <input @keyup.delete="handleDelete">

    <!-- 常用按键别名 -->
    <input @keyup.esc="handleEsc">
    <input @keyup.space="handleSpace">
    <input @keyup.tab="handleTab">
    <input @keyup.up="handleUp">
    <input @keyup.down="handleDown">

    <!-- 使用键码 -->
    <input @keyup.page-down="handlePageDown">
  </div>
</template>

<script setup>
function submit() {
  console.log('提交')
}

function handleDelete() {
  console.log('删除')
}

function handleEsc() {
  console.log('取消')
}

function handleSpace() {
  console.log('空格')
}

function handleTab() {
  console.log('Tab')
}

function handleUp() {
  console.log('向上')
}

function handleDown() {
  console.log('向下')
}

function handlePageDown() {
  console.log('PageDown')
}
</script>

系统修饰键

<template>
  <div>
    <!-- Ctrl + Click -->
    <button @click.ctrl="handleCtrlClick">Ctrl+点击</button>

    <!-- Alt + Enter -->
    <input @keyup.alt.enter="handleAltEnter">

    <!-- Shift + Click -->
    <button @click.shift="handleShiftClick">Shift+点击</button>

    <!-- Meta(Cmd/Win) + Click -->
    <button @click.meta="handleMetaClick">Meta+点击</button>

    <!-- .exact修饰符:精确匹配 -->
    <button @click.ctrl.exact="handleCtrlOnly">只有Ctrl</button>
    <button @click.exact="handleClickOnly">没有修饰键</button>
  </div>
</template>

<script setup>
function handleCtrlClick() {
  console.log('Ctrl + Click')
}

function handleAltEnter() {
  console.log('Alt + Enter')
}

function handleShiftClick() {
  console.log('Shift + Click')
}

function handleMetaClick() {
  console.log('Meta + Click')
}

function handleCtrlOnly() {
  console.log('只按了Ctrl')
}

function handleClickOnly() {
  console.log('没有修饰键')
}
</script>

鼠标按键修饰符

<template>
  <div>
    <button @click.left="handleLeftClick">左键点击</button>
    <button @click.right="handleRightClick">右键点击</button>
    <button @click.middle="handleMiddleClick">中键点击</button>
  </div>
</template>

<script setup>
function handleLeftClick() {
  console.log('左键')
}

function handleRightClick() {
  console.log('右键')
}

function handleMiddleClick() {
  console.log('中键')
}
</script>

实战示例:表单验证

<template>
  <div>
    <form @submit.prevent="handleSubmit">
      <div>
        <label>用户名:</label>
        <input
          v-model="form.username"
          @blur="validateUsername"
          @keyup.enter="handleSubmit"
        >
        <span v-if="errors.username">{{ errors.username }}</span>
      </div>

      <div>
        <label>密码:</label>
        <input
          type="password"
          v-model="form.password"
          @blur="validatePassword"
        >
        <span v-if="errors.password">{{ errors.password }}</span>
      </div>

      <button type="submit">提交</button>
      <button type="button" @click.stop="handleReset">重置</button>
    </form>
  </div>
</template>

<script setup>
import { reactive } from 'vue'

const form = reactive({
  username: '',
  password: ''
})

const errors = reactive({
  username: '',
  password: ''
})

function validateUsername() {
  if (!form.username) {
    errors.username = '用户名不能为空'
  } else if (form.username.length < 3) {
    errors.username = '用户名至少3个字符'
  } else {
    errors.username = ''
  }
}

function validatePassword() {
  if (!form.password) {
    errors.password = '密码不能为空'
  } else if (form.password.length < 6) {
    errors.password = '密码至少6个字符'
  } else {
    errors.password = ''
  }
}

function handleSubmit() {
  validateUsername()
  validatePassword()

  if (!errors.username && !errors.password) {
    console.log('提交表单', form)
    alert('提交成功!')
  }
}

function handleReset() {
  form.username = ''
  form.password = ''
  errors.username = ''
  errors.password = ''
}
</script>

练习

  1. 创建一个计数器,支持增加、减少、重置功能
  2. 实现一个搜索框,按Enter键触发搜索
  3. 创建一个右键菜单,阻止默认的浏览器右键菜单
  4. 实现一个表单,使用各种事件修饰符进行验证