了解“$emit”和事件修饰符
$emit
和 Event Modifier 是构建交互式和动态 Vue.js 应用程序的基本工具。它们使组件能够有效地通信并精确处理用户交互。了解这些概念对于创建可重用、可维护和可扩展的 Vue.js 组件至关重要。本课将深入探讨用于自定义事件创建和处理的 $emit
的复杂性,并探索事件修饰符在 Vue.js 应用程序中简化事件处理的强大功能。
了解 $emit
$emit
方法是 Vue 的组件触发自定义事件的机制。然后,父组件可以监听此事件,从而允许在组件树中向上通信。它是基于组件的架构的基石,使组件能够在与周围环境交互的同时保持独立性。
$emit
的基本用法
最简单的 $emit
形式涉及使用要触发的事件的名称调用方法。例如,如果组件内有一个按钮,并且希望在单击该按钮时通知父级,则可以执行以下作:
<template>
<button @click="handleClick">Click me</button>
</template>
<script>
export default {
methods: {
handleClick() {
this.$emit('custom-click');
}
}
}
</script>
在此示例中,单击按钮时,将执行 handleClick
方法,该方法反过来会发出名为 custom-click
的自定义事件。然后,父组件可以使用 v-on
(或其简写 @
)来监听这个事件。
<template>
<MyComponent @custom-click="handleCustomClick" />
</template>
<script>
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
},
methods: {
handleCustomClick() {
console.log('Custom click event received!');
}
}
}
</script>
使用 $emit
传递数据
通常,您需要将数据与事件一起发送。这可以通过在事件名称后向 $emit
传递其他参数来轻松实现。这些参数将可用于父组件中的事件处理程序。
<template>
<button @click="handleClick">Click me</button>
</template>
<script>
export default {
data() {
return {
message: 'Hello from child!'
};
},
methods: {
handleClick() {
this.$emit('custom-click', this.message);
}
}
}
</script>
现在,父组件可以在处理事件时访问message
:
<template>
<MyComponent @custom-click="handleCustomClick" />
</template>
<script>
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
},
methods: {
handleCustomClick(message) {
console.log('Received message:', message); // Output: Received message: Hello from child!
}
}
}
</script>
事件名称和约定
虽然从技术上讲,你可以使用任何字符串作为事件名称,但最佳做法是使用 kebab-case(例如,custom-click
、item-selected
)。此约定可确保一致性,并避免在不同环境中出现区分大小写的潜在问题。它还提高了可读性。
示例:从表单组件发出数据
考虑一个允许用户输入其姓名和电子邮件的表单组件。提交表单后,组件应发出包含表单数据的事件。
<template>
<form @submit.prevent="handleSubmit">
<label for="name">Name:</label>
<input type="text" id="name" v-model="name">
<label for="email">Email:</label>
<input type="email" id="email" v-model="email">
<button type="submit">Submit</button>
</form>
</template>
<script>
export default {
data() {
return {
name: '',
email: ''
};
},
methods: {
handleSubmit() {
this.$emit('form-submitted', {
name: this.name,
email: this.email
});
}
}
}
</script>
然后,父组件可以侦听表单提交的
事件并访问表单数据:
<template>
<MyForm @form-submitted="handleFormSubmitted" />
</template>
<script>
import MyForm from './MyForm.vue';
export default {
components: {
MyForm
},
methods: {
handleFormSubmitted(formData) {
console.log('Form data received:', formData);
// { name: 'John Doe', email: 'john.doe@example.com' }
}
}
}
</script>
事件修饰符
事件修饰符是用点 (.)
表示的特殊后缀,您可以将其添加到 v-on
指令中以修改事件侦听器的默认行为。它们提供了一种简洁的方法,可以直接在模板中处理与事件相关的常见任务,而无需在组件的方法中编写额外的代码。
.stop
.stop
修饰符调用 event.stopPropagation(),
防止事件在 DOM 树中冒泡。当您想要阻止事件触发父元素上的处理程序时,这很有用。
<template>
<div @click="handleOuterClick">
Outer
<button @click.stop="handleInnerClick">Inner</button>
</div>
</template>
<script>
export default {
methods: {
handleOuterClick() {
console.log('Outer click');
},
handleInnerClick() {
console.log('Inner click');
}
}
}
</script>
在此示例中,单击 “Inner” 按钮将仅触发 handleInnerClick
。.stop
修饰符可防止 click 事件上升到 div
,因此不会调用 handleOuterClick
。
.prevent
.prevent
修饰符调用 event.preventDefault(),
从而阻止事件的默认作。这通常与表单提交一起使用,以防止页面重新加载。
<template>
<form @submit.prevent="handleSubmit">
<button type="submit">Submit</button>
</form>
</template>
<script>
export default {
methods: {
handleSubmit() {
console.log('Form submitted');
}
}
}
</script>
在这种情况下,单击“提交”按钮将触发 handleSubmit
,但由于 .prevent
修饰符,表单实际上不会提交和重新加载页面。
.capture
.capture
修饰符在 capture 模式下添加事件侦听器。这意味着事件侦听器将在附加到捕获元素内的元素的任何事件侦听器之前触发。
<template>
<div @click.capture="handleOuterClick">
Outer
<button @click="handleInnerClick">Inner</button>
</div>
</template>
<script>
export default {
methods: {
handleOuterClick() {
console.log('Outer click (capture)');
},
handleInnerClick() {
console.log('Inner click');
}
}
}
</script>
当您单击“Inner”按钮时,将首先触发 handleOuterClick
(在捕获阶段),然后是 handleInnerClick
(在冒泡阶段)。
.self
仅当事件是从元素本身而不是从子元素调度时,.self
修饰符才会触发处理程序。
<template>
<div @click.self="handleOuterClick">
Outer
<button @click="handleInnerClick">Inner</button>
</div>
</template>
<script>
export default {
methods: {
handleOuterClick() {
console.log('Outer click (self)');
},
handleInnerClick() {
console.log('Inner click');
}
}
}
</script>
直接单击 div
将触发 handleOuterClick
。但是,单击 “Inner” 按钮只会触发 handleInnerClick
,因为该事件源自按钮,而不是 div
本身。
.once
.once
修饰符确保事件侦听器仅触发一次。在第一次触发后,侦听器会自动删除。
<template>
<button @click.once="handleClick">Click me</button>
</template>
<script>
export default {
methods: {
handleClick() {
console.log('Clicked once');
}
}
}
</script>
在此示例中,handleClick
将仅在第一次单击按钮时执行。后续点击将不起作用。
.passive
.passive
修饰符通过指示事件侦听器不会调用 preventDefault()
来提高性能,尤其是在移动设备上。这允许浏览器优化滚动性能。
<template>
<div @scroll.passive="handleScroll">
Scrollable content...
</div>
</template>
<script>
export default {
methods: {
handleScroll() {
console.log('Scrolling');
}
}
}
</script>
使用 .passive
会告诉浏览器 handleScroll
不会阻止默认滚动行为,从而允许更流畅的滚动。
键修饰符:.enter
、.tab
、.delete
、.esc
、.space
、.up
、.down
、.left
、.right
Vue 还提供了监听特定键盘事件的 key modifier。这些修饰符对于处理表单和其他交互式元素中的键盘输入特别有用。
<template>
<input @keyup.enter="handleEnter">
</template>
<script>
export default {
methods: {
handleEnter() {
console.log('Enter key pressed');
}
}
}
</script>
在此示例中,只有在聚焦输入字段时按下 Enter 键时,才会调用 handleEnter
。
您还可以使用特定的键代码:
<template>
<input @keyup.13="handleEnter">
</template>
<script>
export default {
methods: {
handleEnter() {
console.log('Enter key pressed');
}
}
</script>
系统修饰键:.ctrl
、.alt
、.shift
、.meta
仅当同时按下相应的修饰键时,这些修饰符才会触发侦听器。例如,@click.ctrl=“doSomething”
只有在单击时按住 Ctrl 键时才会触发 doSomething
。
鼠标按钮修饰符:.left
、.right
、.middle
这些修饰符将侦听器限制为仅在按下相应的鼠标按钮时触发。
链接修饰符
可以将多个修改器链接在一起以组合其效果。例如,@click.stop.prevent
将停止事件传播并阻止默认作。
示例:实现 Modal 组件
考虑一个模态组件,当用户点击模态内容外部或按下 Escape 键时,该组件应关闭。
<template>
<div class="modal-overlay" @click.self="closeModal">
<div class="modal-content">
<slot></slot>
<button @click="closeModal">Close</button>
</div>
</div>
</template>
<script>
export default {
methods: {
closeModal() {
this.$emit('close');
}
},
mounted() {
document.addEventListener('keyup', this.handleEsc);
},
beforeUnmount() {
document.removeEventListener('keyup', this.handleEsc);
},
methods: {
handleEsc(event) {
if (event.key === 'Escape') {
this.closeModal();
}
}
}
}
</script>
在父组件中:
<template>
<button @click="showModal = true">Open Modal</button>
<MyModal v-if="showModal" @close="showModal = false">
Modal Content
</MyModal>
</template>
<script>
import MyModal from './MyModal.vue';
export default {
components: {
MyModal
},
data() {
return {
showModal: false
};
}
}
</script>