第一部分:Vue 3 基础入门
第9集:事件处理与表单绑定基础
在Vue应用中,事件处理和表单绑定是非常常见的操作。Vue 3提供了简洁、高效的方式来处理用户交互和表单数据。在本集中,我们将学习Vue 3的事件处理和表单绑定基础,包括事件监听、事件修饰符、表单输入绑定等内容。
9.1 事件处理基础
Vue使用v-on指令(简写为@)来监听DOM事件,并在事件触发时执行相应的处理函数。
9.1.1 基本事件监听
示例:
<template>
<div>
<h1>事件处理基础</h1>
<button v-on:click="handleClick">点击我</button>
<button @click="handleClick">点击我(简写)</button>
<p>点击次数: {{ count }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
function handleClick() {
count.value++
}
</script>9.1.2 事件对象
在事件处理函数中,我们可以通过$event访问原生的DOM事件对象。
示例:
<template>
<div>
<h1>事件对象</h1>
<button @click="handleClickWithEvent($event)">点击我</button>
<p>事件类型: {{ eventType }}</p>
<p>点击坐标: {{ x }}, {{ y }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const eventType = ref('')
const x = ref(0)
const y = ref(0)
function handleClickWithEvent(event) {
eventType.value = event.type
x.value = event.clientX
y.value = event.clientY
}
</script>9.1.3 传递参数
我们可以在事件处理函数中传递自定义参数,同时也可以访问事件对象。
示例:
<template>
<div>
<h1>传递参数</h1>
<button @click="handleClickWithParams('hello', $event)">点击我</button>
<p>参数: {{ message }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('')
function handleClickWithParams(param, event) {
message.value = param
console.log('Event:', event.type)
}
</script>9.2 事件修饰符
Vue提供了事件修饰符来处理常见的DOM事件行为,如阻止冒泡、阻止默认行为等。事件修饰符可以链式使用。
9.2.1 常用事件修饰符
.stop:阻止事件冒泡.prevent:阻止默认行为.capture:使用事件捕获模式.self:只当事件目标是元素本身时触发.once:事件只触发一次.passive:告诉浏览器事件监听器不会调用preventDefault()
示例:
<template>
<div>
<h1>事件修饰符</h1>
<!-- 阻止冒泡 -->
<div class="outer" @click="handleOuterClick">
<div class="inner" @click.stop="handleInnerClick">
点击内层div(阻止冒泡)
</div>
</div>
<p>外层点击次数: {{ outerCount }}</p>
<p>内层点击次数: {{ innerCount }}</p>
<!-- 阻止默认行为 -->
<a href="https://example.com" @click.prevent="handleLinkClick">点击链接(阻止跳转)</a>
<p>链接点击次数: {{ linkCount }}</p>
<!-- 只触发一次 -->
<button @click.once="handleOnceClick">点击我(只触发一次)</button>
<p>一次性按钮点击次数: {{ onceCount }}</p>
<!-- 链式修饰符 -->
<form @submit.prevent.stop="handleSubmit">
<button type="submit">提交表单(阻止默认行为和冒泡)</button>
</form>
<p>表单提交次数: {{ submitCount }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const outerCount = ref(0)
const innerCount = ref(0)
const linkCount = ref(0)
const onceCount = ref(0)
const submitCount = ref(0)
function handleOuterClick() {
outerCount.value++
}
function handleInnerClick() {
innerCount.value++
}
function handleLinkClick() {
linkCount.value++
}
function handleOnceClick() {
onceCount.value++
}
function handleSubmit() {
submitCount.value++
}
</script>
<style scoped>
.outer {
width: 200px;
height: 200px;
background-color: #f0f0f0;
padding: 20px;
margin: 20px 0;
}
.inner {
width: 100px;
height: 100px;
background-color: #42b883;
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
</style>9.2.2 按键修饰符
Vue提供了按键修饰符来监听特定的键盘事件。
常用按键修饰符:
.enter:回车键.tab:Tab键.delete:删除键和退格键.esc:Esc键.space:空格键.up:上箭头.down:下箭头.left:左箭头.right:右箭头
示例:
<template>
<div>
<h1>按键修饰符</h1>
<input
type="text"
@keyup.enter="handleEnter"
@keyup.esc="handleEsc"
v-model="inputValue"
placeholder="按下Enter或Esc键"
>
<p>输入内容: {{ inputValue }}</p>
<p>Enter键按下次数: {{ enterCount }}</p>
<p>Esc键按下次数: {{ escCount }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const inputValue = ref('')
const enterCount = ref(0)
const escCount = ref(0)
function handleEnter() {
enterCount.value++
}
function handleEsc() {
escCount.value++
inputValue.value = '' // 清空输入
}
</script>9.3 表单输入绑定
Vue提供了v-model指令来实现表单输入和应用状态之间的双向绑定。
9.3.1 基本用法
示例:
<template>
<div>
<h1>表单输入绑定</h1>
<!-- 文本输入 -->
<div>
<label for="name">姓名:</label>
<input type="text" id="name" v-model="name">
<p>姓名: {{ name }}</p>
</div>
<!-- 多行文本 -->
<div>
<label for="message">留言:</label>
<textarea id="message" v-model="message" rows="3"></textarea>
<p>留言: {{ message }}</p>
<p>字数: {{ message.length }}</p>
</div>
<!-- 复选框 -->
<div>
<label>
<input type="checkbox" v-model="isAgreed">
我同意条款
</label>
<p>是否同意: {{ isAgreed ? '是' : '否' }}</p>
</div>
<!-- 多个复选框 -->
<div>
<h3>选择爱好:</h3>
<label>
<input type="checkbox" v-model="hobbies" value="reading">
阅读
</label>
<label>
<input type="checkbox" v-model="hobbies" value="sports">
运动
</label>
<label>
<input type="checkbox" v-model="hobbies" value="music">
音乐
</label>
<p>选择的爱好: {{ hobbies }}</p>
</div>
<!-- 单选按钮 -->
<div>
<h3>选择性别:</h3>
<label>
<input type="radio" v-model="gender" value="male">
男
</label>
<label>
<input type="radio" v-model="gender" value="female">
女
</label>
<p>选择的性别: {{ gender }}</p>
</div>
<!-- 下拉选择 -->
<div>
<label for="city">选择城市:</label>
<select id="city" v-model="city">
<option value="">请选择</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="guangzhou">广州</option>
<option value="shenzhen">深圳</option>
</select>
<p>选择的城市: {{ city }}</p>
</div>
<!-- 数字输入 -->
<div>
<label for="age">年龄:</label>
<input type="number" id="age" v-model.number="age">
<p>年龄: {{ age }}</p>
<p>年龄类型: {{ typeof age }}</p>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
// 文本输入
const name = ref('')
const message = ref('')
// 复选框
const isAgreed = ref(false)
const hobbies = ref([])
// 单选按钮
const gender = ref('')
// 下拉选择
const city = ref('')
// 数字输入
const age = ref(0)
</script>9.3.2 v-model修饰符
Vue提供了v-model修饰符来处理表单输入的特殊情况。
常用修饰符:
.lazy:在change事件而不是input事件中更新数据.number:自动将输入转换为数字.trim:自动去除输入内容的首尾空格
示例:
<template>
<div>
<h1>v-model修饰符</h1>
<!-- lazy修饰符 -->
<div>
<label for="lazy-input">Lazy输入:</label>
<input type="text" id="lazy-input" v-model.lazy="lazyValue">
<p>输入内容: {{ lazyValue }}</p>
<p>(失去焦点或按下Enter键后更新)</p>
</div>
<!-- number修饰符 -->
<div>
<label for="number-input">数字输入:</label>
<input type="text" id="number-input" v-model.number="numberValue">
<p>输入内容: {{ numberValue }}</p>
<p>类型: {{ typeof numberValue }}</p>
</div>
<!-- trim修饰符 -->
<div>
<label for="trim-input">Trim输入:</label>
<input type="text" id="trim-input" v-model.trim="trimValue">
<p>输入内容: "{{ trimValue }}"</p>
<p>长度: {{ trimValue.length }}</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const lazyValue = ref('')
const numberValue = ref(0)
const trimValue = ref('')
</script>9.4 自定义事件与v-model
我们可以在自定义组件中使用v-model,通过defineProps和defineEmits来实现双向绑定。
示例:
<template>
<div>
<h1>自定义组件的v-model</h1>
<custom-input v-model="customValue" placeholder="输入内容"></custom-input>
<p>自定义输入值: {{ customValue }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import CustomInput from './components/CustomInput.vue'
const customValue = ref('')
</script>CustomInput.vue组件:
<template>
<div class="custom-input">
<input
type="text"
:value="modelValue"
@input="handleInput"
:placeholder="placeholder"
>
</div>
</template>
<script setup>
// 定义props
const props = defineProps({
modelValue: {
type: String,
default: ''
},
placeholder: {
type: String,
default: ''
}
})
// 定义emits
const emit = defineEmits(['update:modelValue'])
// 事件处理
function handleInput(event) {
emit('update:modelValue', event.target.value)
}
</script>
<style scoped>
.custom-input input {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
width: 300px;
}
</style>9.5 表单处理最佳实践
使用
v-model进行双向绑定:- 避免手动操作DOM来获取表单值
- 利用
v-model的修饰符简化数据处理
合理使用事件修饰符:
- 使用
.prevent阻止表单默认提交 - 使用
.stop阻止不必要的事件冒泡 - 使用按键修饰符处理键盘事件
- 使用
表单验证:
- 在提交前进行客户端验证
- 使用计算属性或自定义验证函数
- 考虑使用VeeValidate等表单验证库
处理表单提交:
- 使用
@submit.prevent处理表单提交 - 在提交函数中处理异步请求
- 显示加载状态和错误信息
- 使用
优化用户体验:
- 提供即时反馈
- 使用适当的输入类型(如email、tel等)
- 添加占位符和提示文本
9.6 综合示例:待办事项列表
让我们创建一个综合示例,使用事件处理和表单绑定来实现一个简单的待办事项列表。
示例:
<template>
<div class="todo-app">
<h1>待办事项列表</h1>
<!-- 添加待办事项 -->
<form @submit.prevent="addTodo">
<input
type="text"
v-model="newTodo"
placeholder="添加新的待办事项"
required
>
<button type="submit">添加</button>
</form>
<!-- 待办事项列表 -->
<ul class="todo-list">
<li
v-for="todo in todos"
:key="todo.id"
:class="{ completed: todo.completed }"
>
<input
type="checkbox"
v-model="todo.completed"
@change="saveTodos"
>
<span>{{ todo.text }}</span>
<button @click="deleteTodo(todo.id)">删除</button>
</li>
</ul>
<!-- 统计信息 -->
<div class="stats">
<p>总数量: {{ todos.length }}</p>
<p>已完成: {{ completedCount }}</p>
<p>未完成: {{ remainingCount }}</p>
</div>
<!-- 清除已完成 -->
<button @click="clearCompleted" :disabled="completedCount === 0">
清除已完成
</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
// 待办事项列表
const todos = ref([
{ id: 1, text: '学习Vue 3', completed: false },
{ id: 2, text: '创建待办事项应用', completed: false },
{ id: 3, text: '提交代码', completed: false }
])
// 新待办事项
const newTodo = ref('')
// 计算属性
const completedCount = computed(() => {
return todos.value.filter(todo => todo.completed).length
})
const remainingCount = computed(() => {
return todos.value.filter(todo => !todo.completed).length
})
// 方法
function addTodo() {
if (newTodo.value.trim()) {
todos.value.push({
id: Date.now(),
text: newTodo.value.trim(),
completed: false
})
newTodo.value = ''
saveTodos()
}
}
function deleteTodo(id) {
todos.value = todos.value.filter(todo => todo.id !== id)
saveTodos()
}
function clearCompleted() {
todos.value = todos.value.filter(todo => !todo.completed)
saveTodos()
}
function saveTodos() {
// 这里可以保存到localStorage或发送到服务器
localStorage.setItem('todos', JSON.stringify(todos.value))
}
// 初始化时从localStorage加载数据
const savedTodos = localStorage.getItem('todos')
if (savedTodos) {
todos.value = JSON.parse(savedTodos)
}
</script>
<style scoped>
.todo-app {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
form {
display: flex;
margin-bottom: 20px;
}
input[type="text"] {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
margin-right: 10px;
}
button {
padding: 8px 16px;
background-color: #42b883;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #3aa876;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.todo-list {
list-style: none;
padding: 0;
margin-bottom: 20px;
}
.todo-list li {
display: flex;
align-items: center;
padding: 10px;
border-bottom: 1px solid #eee;
}
.todo-list li.completed span {
text-decoration: line-through;
color: #999;
}
.todo-list li span {
flex: 1;
margin: 0 10px;
}
.stats {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
font-size: 14px;
color: #666;
}
</style>本集小结
在本集中,我们学习了Vue 3的事件处理和表单绑定基础:
事件处理:
- 使用
v-on或@监听事件 - 访问事件对象和传递参数
- 使用事件修饰符处理常见的DOM行为
- 使用按键修饰符处理键盘事件
- 使用
表单输入绑定:
- 使用
v-model实现双向绑定 - 支持文本、多行文本、复选框、单选按钮、下拉选择等
- 使用
v-model修饰符(.lazy、.number、.trim) - 在自定义组件中使用
v-model
- 使用
最佳实践:
- 合理使用
v-model和事件修饰符 - 进行表单验证
- 优化用户体验
- 处理表单提交和异步请求
- 合理使用
综合示例:
- 实现了一个待办事项列表,包含添加、删除、标记完成等功能
- 使用了localStorage进行数据持久化
事件处理和表单绑定是Vue应用开发中的核心功能,掌握好这些知识可以帮助我们创建交互丰富、用户体验良好的应用。在下一集中,我们将学习Vue 3的条件渲染与列表渲染,进一步提升我们的Vue开发能力。