Skip to content

VueJS - 事件

Vue 允许你使用 v-on 指令(或其简写形式 @)来监听 DOM 事件,并在这些事件触发时运行 JavaScript 代码。本章将介绍 Vue 3 中事件处理的各个方面。

你可以使用 v-on:eventname 或简写形式 @eventname 来为元素附加事件监听器。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 Click Event</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="app-click">
<button v-on:click="incrementCounter">Click Me (v-on)</button>
<button @click="incrementCounter">Click Me (@)</button>
<p>Counter: {{ counter }}</p>
<button @click="greet('Hello Vue!')">Greet</button>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const counter = ref(0);
function incrementCounter() {
counter.value++;
console.log('Counter incremented!');
}
function greet(message) {
alert(message);
}
return {
counter,
incrementCounter,
greet
};
}
}).mount('#app-click');
</script>
</body>
</html>
  • v-on:click="incrementCounter" 或 @click="incrementCounter" 在点击按钮时调用 incrementCounter 方法。
  • 在 Composition API 中,方法定义在 setup() 函数内部。
  • 你可以直接在模板中传递参数,例如 @click="greet('Hello Vue!')"。
  • 如果你需要访问原始的 DOM 事件对象,在没有传递其他参数时,你可以自动接收它(incrementCounter 可以接受 event 作为其第一个参数);或者通过特殊的 $event 变量显式传递它:@click="handleEvent($event, 'some value')"。

示例:鼠标事件 (mouseover, mouseout)

Section titled “示例:鼠标事件 (mouseover, mouseout)”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 Mouse Events</title>
<script src="https://unpkg.com/vue@3"></script>
<style>
.hover-box {
width: 150px;
height: 100px;
border: 1px solid black;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: background-color 0.3s ease;
}
</style>
</head>
<body>
<div id="app-mouse">
<div
class="hover-box"
:style="{ backgroundColor: boxColor }"
@mouseover="changeColor('lightgreen')"
@mouseout="changeColor('lightblue')">
Hover over me!
</div>
<p>Current Box Color: {{ boxColor }}</p>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const boxColor = ref('lightblue'); // Initial color
function changeColor(newColor) {
boxColor.value = newColor;
}
return {
boxColor,
changeColor
};
}
}).mount('#app-mouse');
</script>
</body>
</html>
  • 该 div 监听 mouseover 和 mouseout 事件。
  • 事件发生时,会调用 changeColor 方法,并传入所需的颜色字符串。
  • 背景颜色使用 :style 动态绑定到 boxColor 这个 reactive (响应式)变量上。

Vue 提供了事件修饰符,用于直接在模板中处理一些常见的任务。修饰符是添加在事件名称后面的后缀,用点 (.) 分隔:

  • .stop: 调用 event.stopPropagation()。
  • .prevent: 调用 event.preventDefault()。
  • .capture: 在捕获模式下添加事件监听器。
  • .self: 只有当事件是从该元素自身触发时才触发处理函数(而不是来自子元素)。
  • .once: 处理函数最多触发一次。
  • .passive: 提高移动设备上滚动事件的性能(对应于 addEventListener 的 passive 选项)。
<div id="app-modifiers">
<!-- Prevent default form submission -->
<form @submit.prevent="onSubmit">
<input type="text" placeholder="Enter something">
<button type="submit">Submit (No Page Reload)</button>
</form>
<!-- Button that can only be clicked once -->
<button @click.once="doOnce">Click Me Only Once</button>
<p>Once Click Count: {{ onceCount }}</p>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const onceCount = ref(0);
function onSubmit() {
alert('Form submitted via Vue (page did not reload)!');
}
function doOnce() {
onceCount.value++;
alert('This alert appears only once!');
}
return { onSubmit, doOnce, onceCount };
}
}).mount('#app-modifiers');
</script>

.prevent 阻止表单的默认提交行为(页面刷新)。.once 确保 doOnce 方法只在按钮第一次被点击时调用。

Vue 允许你使用按键修饰符,仅当用户按下特定按键时才触发事件处理函数。

  • .enter
  • .tab
  • .delete (捕获 ‘Delete’ 和 ‘Backspace’ 键)
  • .esc
  • .space
  • .up, .down, .left, .right (方向键)
  • 系统修饰符:.ctrl, .alt, .shift, .meta (Mac 上的 Command 键,Windows 上的 Windows 键)
<div id="app-keys">
<label>Submit on Enter:</label>
<input type="text" v-model="message" @keyup.enter="submitMessage" placeholder="Type and press Enter">
<p>Submitted: {{ submittedMessage }}</p>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const message = ref('');
const submittedMessage = ref('');
function submitMessage() {
submittedMessage.value = message.value;
message.value = ''; // Clear input
alert('Message submitted!');
}
return { message, submittedMessage, submitMessage };
}
}).mount('#app-keys');
</script>

只有当用户在输入框中按下并释放 ‘Enter’ 键时,才会调用 submitMessage 方法。

自定义事件(子组件向父组件通信)

Section titled “自定义事件(子组件向父组件通信)”

组件可以使用 $emit 方法触发自定义事件。父组件可以使用 v-on 或 @ 监听这些事件。

<div id="app-custom-event">
<p>Selected Language: {{ selectedLanguage || 'None' }}</p>
<!-- Child component emitting 'language-selected' event -->
<language-selector
:languages="availableLanguages"
@language-selected="handleLanguageSelection">
</language-selector>
</div>
<script>
const { createApp, ref } = Vue;
const app = createApp({
setup() {
const selectedLanguage = ref('');
const availableLanguages = ref(['JavaScript', 'Python', 'Java', 'C#']);
function handleLanguageSelection(language) {
selectedLanguage.value = language;
console.log(`Parent received selected language: ${language}`);
}
return {
selectedLanguage,
availableLanguages,
handleLanguageSelection
};
}
});
// Child Component: LanguageSelector
app.component('language-selector', {
props: {
languages: { type: Array, required: true }
},
emits: ['language-selected'], // 最佳实践:声明要触发的事件
template: `
<div>
<button
v-for="lang in languages"
:key="lang"
@click="selectLanguage(lang)"
style="margin: 5px; font-size: 1em;">
{{ lang }}
</button>
</div>
`,
methods: {
selectLanguage(lang) {
// 触发事件,并将选中的语言作为载荷(payload)传递
this.$emit('language-selected', lang);
}
}
// 在组件的 Composition API setup 函数中:
/*
setup(props, { emit }) {
function selectLanguage(lang) {
emit('language-selected', lang);
}
return { selectLanguage };
}
*/
});
app.mount('#app-custom-event');
</script>
  • language-selector 子组件通过 props 接收语言列表。
  • 当子组件中的按钮被点击时,其 selectLanguage 方法会调用 this.$emit('language-selected', lang)。这会将 language-selected 事件向上发送给父组件,并将选定的语言 (lang) 作为数据 (载荷/payload) 传递。
  • 父组件使用 @language-selected="handleLanguageSelection" 在 <language-selector> 标签上监听此事件。
  • 父组件的 handleLanguageSelection 方法接收到载荷(选定的语言)并更新 selectedLanguage 状态。
  • 在子组件中使用 emits: ['language-selected'] 声明要触发的事件,这是 Vue 3 中推荐的做法,可以提高代码清晰度并可能带来未来的优化。

事件处理是构建交互式应用的基础。Vue 的系统,包括 v-on、修饰符和 $emit,提供了一种强大且声明式的方式来管理用户交互和组件通信。