Vue事件綁定完全指南之官方文檔未詳述的事件大全
前言
Vue 的 v-on(即 @)本質(zhì)上是對原生 DOM 事件的直接透傳,凡是瀏覽器原生支持的事件,Vue 均可綁定。本文系統(tǒng)整理官方文檔未重點列出、但實際開發(fā)中極具價值的各類事件,并附帶修飾符組合、編譯器處理機制與架構(gòu)層面的深度說明。
一、編譯器如何處理事件名
理解 Vue 如何處理事件名,是掌握所有事件綁定的基礎(chǔ)。
1.1 事件名轉(zhuǎn)換規(guī)則
Vue 編譯器(@vue/compiler-dom)在處理 @eventName 時執(zhí)行以下轉(zhuǎn)換:
模板寫法 → 編譯產(chǎn)物(props key) @click → onClick @dblclick → onDblclick @mouseenter → onMouseenter @keydown.enter → onKeydown(運行時過濾 key) @update:modelValue → onUpdate:modelValue
核心轉(zhuǎn)換函數(shù)來自 @vue/shared:
import { toHandlerKey, camelize } from '@vue/shared'
toHandlerKey('click') // 'onClick'
toHandlerKey('dblclick') // 'onDblclick'
toHandlerKey(camelize('my-event')) // 'onMyEvent'
1.2 事件名大小寫規(guī)則
<!-- 以下三種寫法在組件上等價(Vue 自動轉(zhuǎn)換) --> @myEvent="handler" @my-event="handler" @my_event="handler" <!-- 原生 DOM 元素上:保持原始大小寫,不做轉(zhuǎn)換 --> <div @dblclick="handler" /> <!-- ? 正確 --> <div @DblClick="handler" /> <!-- ? 無法觸發(fā)(原生事件名全小寫) -->
二、鼠標(biāo)事件(Mouse Events)
2.1 文檔常見事件
@click <!-- 單擊 --> @mouseover <!-- 鼠標(biāo)懸入(含子元素冒泡) --> @mouseout <!-- 鼠標(biāo)離開(含子元素冒泡) --> @mousemove <!-- 鼠標(biāo)移動 --> @mousedown <!-- 鼠標(biāo)按下 --> @mouseup <!-- 鼠標(biāo)抬起 --> @contextmenu <!-- 右鍵菜單 -->
2.2 文檔未重點說明的鼠標(biāo)事件
@dblclick— 雙擊
<div @dblclick="onDblClick">雙擊我</div>
function onDblClick(event: MouseEvent) {
// event.detail === 2,表示這是第二次點擊
console.log('雙擊坐標(biāo):', event.clientX, event.clientY)
}
注意:@click 和 @dblclick 同時綁定時,雙擊會先觸發(fā)兩次 click 再觸發(fā)一次 dblclick。如需互斥,需手動用定時器處理:
let clickTimer: ReturnType<typeof setTimeout> | null = null
function handleClick() {
if (clickTimer) return // 等待期間忽略單擊
clickTimer = setTimeout(() => {
clickTimer = null
doSingleClick()
}, 250)
}
function handleDblClick() {
if (clickTimer) {
clearTimeout(clickTimer)
clickTimer = null
}
doDblClick()
}
@mouseenter/@mouseleave— 不冒泡的懸停事件
<!-- mouseover/mouseout 會因子元素冒泡頻繁觸發(fā) -->
<!-- mouseenter/mouseleave 只在進(jìn)入/離開元素本身時觸發(fā)一次 -->
<div
@mouseenter="isHovered = true"
@mouseleave="isHovered = false"
:class="{ hovered: isHovered }"
>
懸停區(qū)域(推薦用這對,而非 mouseover/mouseout)
</div>
架構(gòu)建議:絕大多數(shù)懸停交互應(yīng)使用 mouseenter/mouseleave 而非 mouseover/mouseout,后者在子元素多的情況下會產(chǎn)生大量無意義的事件觸發(fā)。
@auxclick— 非主鍵點擊(中鍵/側(cè)鍵)
<!-- 鼠標(biāo)中鍵或其他非左鍵的點擊 --> <a @auxclick.prevent="openInNewTab(url)">中鍵點擊新標(biāo)簽打開</a>
function onAuxClick(event: MouseEvent) {
if (event.button === 1) {
// button 1 = 中鍵
event.preventDefault() // 阻止中鍵默認(rèn)的自動滾動
window.open(url, '_blank')
}
}
@click的button屬性區(qū)分左中右鍵
<div @mousedown="handleMouseDown">多鍵區(qū)域</div>
function handleMouseDown(event: MouseEvent) {
switch (event.button) {
case 0: console.log('左鍵'); break
case 1: console.log('中鍵'); break
case 2: console.log('右鍵(通常觸發(fā) contextmenu)'); break
case 3: console.log('側(cè)鍵后退'); break
case 4: console.log('側(cè)鍵前進(jìn)'); break
}
}
@click的鼠標(biāo)按鍵修飾符
<!-- Vue 內(nèi)置的鼠標(biāo)按鍵修飾符(文檔有但常被忽視) --> <div @click.left="onLeft">僅左鍵觸發(fā)</div> <div @click.right="onRight">僅右鍵觸發(fā)(不顯示系統(tǒng)菜單)</div> <div @click.middle="onMiddle">僅中鍵觸發(fā)</div>
三、鍵盤事件(Keyboard Events)
3.1 基礎(chǔ)事件
@keydown <!-- 按鍵按下(持續(xù)觸發(fā)) --> @keyup <!-- 按鍵抬起 --> @keypress <!-- ?? 已廢棄,不推薦使用 -->
3.2 按鍵修飾符完整列表
Vue 內(nèi)置了以下按鍵別名,但文檔中許多組合從未被舉例:
<!-- 字母數(shù)字類 --> @keydown.enter="submit" @keydown.tab="onTab" @keydown.delete="onDelete" <!-- 同時匹配 Delete 和 Backspace --> @keydown.esc="onEsc" <!-- 等價于 Escape --> @keydown.space="onSpace" @keydown.up="moveUp" @keydown.down="moveDown" @keydown.left="moveLeft" @keydown.right="moveRight" <!-- 功能鍵修飾符(可組合) --> @keydown.ctrl.enter="submitForm" <!-- Ctrl + Enter --> @keydown.shift.enter="newline" <!-- Shift + Enter --> @keydown.alt.left="goBack" <!-- Alt + ← --> @keydown.meta.k="openCommandPalette" <!-- Cmd/Win + K --> @keydown.ctrl.shift.z="redo" <!-- Ctrl + Shift + Z --> <!-- 直接使用 KeyboardEvent.key 值(kebab-case) --> @keydown.page-up="scrollUp" @keydown.page-down="scrollDown" @keydown.home="gotoTop" @keydown.end="gotoBottom" @keydown.f1="showHelp" @keydown.f11="toggleFullscreen" <!-- 精確修飾符:只匹配完全一致的按鍵組合 --> @keydown.exact.ctrl.a="selectAll" <!-- 只有 Ctrl+A,有其他鍵不觸發(fā) -->
3.3 自定義按鍵別名(Vue 2 遺留,Vue 3 移除)
Vue 3 已移除 Vue.config.keyCodes,推薦直接使用 KeyboardEvent.key 的 kebab-case 形式:
<!-- Vue 3 直接使用原生 key 名 --> @keydown.arrow-up="moveUp" @keydown.home="gotoTop" @keydown.escape="close" @keydown.tab="focusNext"
3.4 IME 輸入法相關(guān)事件(極重要但完全未文檔化)
<!-- compositionstart: 開始輸入法輸入(中日韓輸入時) --> <!-- compositionupdate: 輸入法候選字更新 --> <!-- compositionend: 輸入法輸入完成,確認(rèn)上屏 --> <input @compositionstart="isComposing = true" @compositionupdate="onCompositionUpdate" @compositionend="isComposing = false; onInput($event)" @input="!isComposing && onInput($event)" />
const isComposing = ref(false)
// 正確處理中文輸入的搜索框
function onInput(event: Event) {
if (isComposing.value) return // 輸入法選字過程中不觸發(fā)搜索
const value = (event.target as HTMLInputElement).value
doSearch(value)
}
這是處理中文/日文/韓文輸入時最常見的坑,v-model 內(nèi)部已處理此問題,但手動監(jiān)聽 @input 時必須自行處理。
四、表單與輸入事件(Form & Input Events)
4.1@inputvs@change的區(qū)別
<!-- @input:每次值變化立即觸發(fā)(包括輸入法過程中) --> <input @input="onInput" /> <!-- @change:失去焦點且值有變化時觸發(fā)(或按 Enter) --> <input @change="onChange" /> <!-- select 元素 --> <select @change="onSelect"> <option>A</option> </select> <!-- checkbox/radio --> <input type="checkbox" @change="onCheckboxChange" />
4.2 焦點事件
@focus <!-- 獲得焦點(不冒泡) --> @blur <!-- 失去焦點(不冒泡) --> @focusin <!-- 獲得焦點(冒泡,可在父元素監(jiān)聽子元素焦點) --> @focusout <!-- 失去焦點(冒泡) -->
<!-- 實用場景:監(jiān)聽整個表單區(qū)域內(nèi)的焦點狀態(tài) --> <div @focusin="isFormActive = true" @focusout="isFormActive = false" > <input placeholder="字段1" /> <input placeholder="字段2" /> </div>
focusin/focusout 會冒泡,而 focus/blur 不會——這是在父容器層面感知子元素焦點的標(biāo)準(zhǔn)方式。
4.3@reset/@submit
<!-- 原生 form 事件 --> <form @submit.prevent="handleSubmit" @reset="handleReset" > <input type="text" /> <button type="submit">提交</button> <button type="reset">重置</button> </form>
4.4@invalid— 原生表單驗證失敗
<!-- 原生 HTML5 表單驗證失敗時觸發(fā) --> <input type="email" required @invalid.prevent="showCustomError($event)" />
function showCustomError(event: Event) {
const input = event.target as HTMLInputElement
// 阻止瀏覽器默認(rèn)氣泡提示,使用自定義 UI
input.setCustomValidity('請輸入有效的郵箱地址')
}
4.5@select— 文本選中
<!-- 用戶在 input/textarea 中選中文字時觸發(fā) --> <textarea @select="onTextSelect" />
function onTextSelect(event: Event) {
const textarea = event.target as HTMLTextAreaElement
const selectedText = textarea.value.slice(
textarea.selectionStart!,
textarea.selectionEnd!
)
console.log('選中的文字:', selectedText)
}
五、拖拽事件(Drag & Drop Events)
這是文檔中完全沒有專門章節(jié)講解的一類事件,但實現(xiàn)原生拖拽時必須用到。
<!-- 被拖拽的元素上 --> <div draggable="true" @dragstart="onDragStart" <!-- 開始拖拽 --> @drag="onDragging" <!-- 拖拽中(持續(xù)觸發(fā)) --> @dragend="onDragEnd" <!-- 拖拽結(jié)束(無論是否成功) --> > 拖我 </div> <!-- 放置目標(biāo)上 --> <div @dragenter="onDragEnter" <!-- 拖拽元素進(jìn)入目標(biāo)區(qū)域 --> @dragover.prevent="onDragOver" <!-- 必須 prevent 才能觸發(fā) drop! --> @dragleave="onDragLeave" <!-- 拖拽元素離開目標(biāo)區(qū)域 --> @drop.prevent="onDrop" <!-- 放置 --> > 放這里 </div>
function onDragStart(event: DragEvent) {
event.dataTransfer!.setData('text/plain', 'payload-data')
event.dataTransfer!.effectAllowed = 'move' // 'copy' | 'move' | 'link'
}
function onDrop(event: DragEvent) {
const data = event.dataTransfer!.getData('text/plain')
console.log('接收到:', data)
}
@dragover.prevent 是關(guān)鍵:不調(diào)用 preventDefault() 的話,@drop 事件永遠(yuǎn)不會觸發(fā)。
5.1 文件拖拽上傳
<div @dragover.prevent @drop.prevent="onFileDrop" class="upload-zone" > 拖拽文件到此處上傳 </div>
function onFileDrop(event: DragEvent) {
const files = Array.from(event.dataTransfer!.files)
files.forEach(file => {
console.log('文件名:', file.name, '大小:', file.size)
uploadFile(file)
})
}
六、剪貼板事件(Clipboard Events)
<input @cut="onCut" @copy="onCopy" @paste="onPaste" />
function onCopy(event: ClipboardEvent) {
// 修改復(fù)制的內(nèi)容
event.preventDefault()
const selection = window.getSelection()?.toString() ?? ''
event.clipboardData!.setData('text/plain', `${selection} —— 來自我的網(wǎng)站`)
}
function onPaste(event: ClipboardEvent) {
event.preventDefault()
const text = event.clipboardData!.getData('text/plain')
// 過濾內(nèi)容后再插入
const sanitized = sanitizeHtml(text)
document.execCommand('insertText', false, sanitized)
}
// 讀取粘貼的文件(如截圖)
function onPasteWithFile(event: ClipboardEvent) {
const items = Array.from(event.clipboardData!.items)
const imageItem = items.find(item => item.type.startsWith('image/'))
if (imageItem) {
const file = imageItem.getAsFile()!
uploadImage(file)
}
}
七、滾動與視口事件
7.1@scroll
<!-- 元素滾動(注意:不冒泡,需綁在實際滾動的元素上) --> <div class="scroll-container" @scroll="onScroll"> <div class="content">長內(nèi)容...</div> </div>
function onScroll(event: Event) {
const el = event.target as HTMLElement
const { scrollTop, scrollHeight, clientHeight } = el
// 判斷是否滾動到底部
if (scrollTop + clientHeight >= scrollHeight - 10) {
loadMore()
}
}
7.2@wheel— 鼠標(biāo)滾輪
<!-- wheel 比 scroll 更底層,可以阻止?jié)L動 --> <div @wheel.prevent="onWheel">阻止此區(qū)域的頁面滾動</div>
function onWheel(event: WheelEvent) {
event.deltaY // 垂直滾動量(正值向下,負(fù)值向上)
event.deltaX // 水平滾動量
event.deltaMode // 0=像素, 1=行, 2=頁
}
@scroll 無法 preventDefault(),@wheel 可以——兩者用途不同。
八、觸摸事件(Touch Events)
<div @touchstart="onTouchStart" <!-- 手指接觸屏幕 --> @touchmove.prevent="onTouchMove" <!-- 手指移動(prevent 阻止頁面滾動) --> @touchend="onTouchEnd" <!-- 手指抬起 --> @touchcancel="onTouchCancel" <!-- 觸摸被中斷(來電等) --> > 觸摸區(qū)域 </div>
let startX = 0
let startY = 0
function onTouchStart(event: TouchEvent) {
startX = event.touches[0].clientX
startY = event.touches[0].clientY
}
function onTouchEnd(event: TouchEvent) {
const endX = event.changedTouches[0].clientX
const endY = event.changedTouches[0].clientY
const dx = endX - startX
const dy = endY - startY
// 簡單滑動手勢識別
if (Math.abs(dx) > Math.abs(dy)) {
dx > 0 ? emit('swipe-right') : emit('swipe-left')
} else {
dy > 0 ? emit('swipe-down') : emit('swipe-up')
}
}
8.1 指針事件(Pointer Events)— 統(tǒng)一鼠標(biāo)+觸摸+筆
<!-- PointerEvent 是鼠標(biāo)事件 + 觸摸事件的統(tǒng)一抽象(推薦使用) --> <div @pointerdown="onPointerDown" @pointermove="onPointerMove" @pointerup="onPointerUp" @pointerenter="onPointerEnter" @pointerleave="onPointerLeave" @pointercancel="onPointerCancel" @gotpointercapture="onGotCapture" @lostpointercapture="onLostCapture" > </div>
function onPointerDown(event: PointerEvent) {
event.pointerId // 指針 ID(多點觸控時區(qū)分不同手指)
event.pointerType // 'mouse' | 'pen' | 'touch'
event.pressure // 壓力值 0-1(筆/觸控板支持)
event.tiltX // 筆的傾斜角
event.isPrimary // 是否是主指針(多點觸控時第一個接觸的手指)
// 捕獲指針:即使鼠標(biāo)移出元素也繼續(xù)接收事件
;(event.target as HTMLElement).setPointerCapture(event.pointerId)
}
架構(gòu)建議:新項目的拖拽、繪圖、手勢等功能優(yōu)先使用 Pointer Events,而非分別處理 Mouse Events 和 Touch Events。**
九、媒體事件(Media Events)
這是文檔完全沒有覆蓋的一類,對音視頻開發(fā)至關(guān)重要。
<video ref="videoRef" @loadstart="onLoadStart" <!-- 開始加載 --> @loadedmetadata="onMetaLoaded" <!-- 元數(shù)據(jù)加載完成(可獲取時長、尺寸) --> @loadeddata="onDataLoaded" <!-- 當(dāng)前幀數(shù)據(jù)加載完成 --> @canplay="onCanPlay" <!-- 可以開始播放 --> @canplaythrough="onCanPlayThrough" <!-- 預(yù)計不會緩沖中斷地播放到結(jié)束 --> @play="onPlay" <!-- 開始播放 --> @playing="onPlaying" <!-- 在緩沖后恢復(fù)播放 --> @pause="onPause" <!-- 暫停 --> @ended="onEnded" <!-- 播放結(jié)束 --> @timeupdate="onTimeUpdate" <!-- 播放進(jìn)度更新(約每秒 4-66 次) --> @seeking="onSeeking" <!-- 用戶拖拽進(jìn)度條中 --> @seeked="onSeeked" <!-- 拖拽完成 --> @waiting="onWaiting" <!-- 緩沖中,等待數(shù)據(jù) --> @stalled="onStalled" <!-- 瀏覽器嘗試獲取數(shù)據(jù)但暫停 --> @error="onError" <!-- 加載/播放錯誤 --> @volumechange="onVolumeChange" <!-- 音量或靜音狀態(tài)變化 --> @ratechange="onRateChange" <!-- 播放速率變化 --> @durationchange="onDurChange" <!-- 時長變化 --> @progress="onProgress" <!-- 下載進(jìn)度更新 --> @suspend="onSuspend" <!-- 瀏覽器停止加載(數(shù)據(jù)已足夠) --> @abort="onAbort" <!-- 資源加載中止(非錯誤) --> @emptied="onEmptied" <!-- 媒體資源被清空 --> > </video>
function onTimeUpdate(event: Event) {
const video = event.target as HTMLVideoElement
const progress = (video.currentTime / video.duration) * 100
progressBar.value = progress
}
function onMetaLoaded(event: Event) {
const video = event.target as HTMLVideoElement
console.log('視頻時長:', video.duration)
console.log('視頻尺寸:', video.videoWidth, 'x', video.videoHeight)
}
十、窗口與文檔事件(配合useEventListener)
這類事件不能直接在 Vue 模板中用 @ 綁定,需要在 onMounted 中手動注冊,或使用 VueUse 的 useEventListener。
import { onMounted, onUnmounted } from 'vue'
// 方式一:手動管理
onMounted(() => {
window.addEventListener('resize', onResize)
window.addEventListener('online', onOnline)
window.addEventListener('offline', onOffline)
document.addEventListener('visibilitychange', onVisibilityChange)
})
onUnmounted(() => {
window.removeEventListener('resize', onResize)
// ...
})
// 方式二:VueUse(推薦)
import { useEventListener } from '@vueuse/core'
useEventListener(window, 'resize', onResize)
useEventListener(document, 'visibilitychange', onVisibilityChange)
常見窗口級事件清單
// 視口
window.addEventListener('resize', handler) // 窗口大小變化
window.addEventListener('scroll', handler) // 窗口滾動
window.addEventListener('orientationchange', handler) // 屏幕旋轉(zhuǎn)
// 網(wǎng)絡(luò)狀態(tài)
window.addEventListener('online', handler) // 網(wǎng)絡(luò)恢復(fù)
window.addEventListener('offline', handler) // 網(wǎng)絡(luò)斷開
// 頁面生命周期
window.addEventListener('load', handler) // 頁面全部資源加載完畢
window.addEventListener('beforeunload', handler) // 頁面即將卸載(可彈確認(rèn)框)
window.addEventListener('unload', handler) // 頁面卸載中
window.addEventListener('pagehide', handler) // 頁面隱藏(bfcache 友好)
window.addEventListener('pageshow', handler) // 頁面顯示
// 歷史記錄
window.addEventListener('popstate', handler) // 瀏覽器前進(jìn)/后退
window.addEventListener('hashchange', handler) // hash 變化
// 焦點
window.addEventListener('focus', handler) // 窗口獲得焦點
window.addEventListener('blur', handler) // 窗口失去焦點
// 文檔可見性
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
pauseVideo() // 切換標(biāo)簽頁時暫停視頻
}
})
// 存儲
window.addEventListener('storage', (event: StorageEvent) => {
// 跨標(biāo)簽頁的 localStorage 變化通知
console.log(event.key, event.oldValue, event.newValue)
})
// 全屏
document.addEventListener('fullscreenchange', handler)
// 打印
window.addEventListener('beforeprint', handler)
window.addEventListener('afterprint', handler)
// 游戲手柄
window.addEventListener('gamepadconnected', handler)
window.addEventListener('gamepaddisconnected', handler)
十一、Intersection Observer 事件(元素進(jìn)入視口)
這不是傳統(tǒng) DOM 事件,但在 Vue 中有標(biāo)準(zhǔn)的封裝方式,常用于懶加載:
// 自定義指令實現(xiàn) v-intersect
const vIntersect = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
binding.value(entry)
if (binding.modifiers.once) {
observer.unobserve(el)
}
}
})
},
{
threshold: binding.arg ? parseFloat(binding.arg as string) : 0,
rootMargin: '0px 0px -50px 0px'
}
)
observer.observe(el)
;(el as any).__intersectObserver__ = observer
},
unmounted(el: HTMLElement) {
;(el as any).__intersectObserver__?.disconnect()
}
}
// 使用
app.directive('intersect', vIntersect)
<img v-intersect.once="onVisible" :src="placeholder" data-src="real-image.jpg" />
十二、自定義組件事件
12.1defineEmits完整用法
// 帶類型驗證(運行時 + 編譯時雙重驗證)
const emit = defineEmits<{
change: [value: string] // 單參數(shù)
update: [id: number, value: string] // 多參數(shù)
'node:select': [node: TreeNode] // 帶命名空間的事件名
submit: [data: FormData, reset: () => void] // 包含回調(diào)函數(shù)參數(shù)
}>()
// 或帶運行時驗證的對象語法
const emit = defineEmits({
change: (value: string) => {
// 返回 false 表示驗證失敗,控制臺輸出警告
return typeof value === 'string' && value.length > 0
},
submit: null // null 表示不驗證
})
12.2v-model多綁定(Vue 3.4+)
<!-- 父組件 --> <MyForm v-model:title="title" v-model:content="content" v-model:tags="tags" />
// 子組件
const props = defineProps<{
title: string
content: string
tags: string[]
}>()
const emit = defineEmits<{
'update:title': [value: string]
'update:content': [value: string]
'update:tags': [value: string[]]
}>()
12.3v-model修飾符透傳
<!-- 父 --> <MyInput v-model.trim.uppercase="text" />
// 子組件處理修飾符
const props = defineProps<{
modelValue: string
modelModifiers?: {
trim?: boolean
uppercase?: boolean
}
}>()
const emit = defineEmits<{
'update:modelValue': [value: string]
}>()
function onInput(event: Event) {
let value = (event.target as HTMLInputElement).value
if (props.modelModifiers?.trim) value = value.trim()
if (props.modelModifiers?.uppercase) value = value.toUpperCase()
emit('update:modelValue', value)
}
十三、修飾符組合速查表
事件修飾符(可鏈?zhǔn)浇M合): .stop → event.stopPropagation() .prevent → event.preventDefault() .self → 只有 event.target === 當(dāng)前元素時觸發(fā) .capture → 使用捕獲模式(從上到下,而非冒泡) .once → 只觸發(fā)一次,之后自動移除監(jiān)聽 .passive → 告知瀏覽器不調(diào)用 preventDefault(scroll 性能優(yōu)化) .native → ?? Vue 3 已移除,請用 v-bind="$attrs" 透傳 .exact → 精確匹配按鍵組合,不允許其他修飾鍵 實用組合: @click.stop.prevent → 阻止冒泡 + 阻止默認(rèn)行為 @scroll.passive → 高性能滾動監(jiān)聽(不能與 .prevent 同用) @keydown.ctrl.exact.s → 精確的 Ctrl+S(有其他鍵不觸發(fā)) @click.once → 按鈕防重復(fù)點擊(僅首次有效) @touchmove.prevent → 阻止移動端頁面隨手勢滾動
十四、在 Render Function 中綁定事件
import { h, withModifiers } from 'vue'
// withModifiers:在 render function 中應(yīng)用事件修飾符
h('button', {
onClick: withModifiers(
(event: MouseEvent) => { console.log('clicked') },
['stop', 'prevent'] // 等價于 @click.stop.prevent
)
})
// 多事件監(jiān)聽
h('input', {
onInput: handler1,
onChange: handler2,
'onUpdate:modelValue': (val) => (modelValue.value = val)
})
// 動態(tài)事件名
const eventName = 'onClick'
h('div', { [eventName]: handler })
總結(jié)
Vue 的事件系統(tǒng)本質(zhì)上是對原生 DOM 事件的完整代理。所有瀏覽器原生事件均可通過 @eventName 直接綁定,編譯器負(fù)責(zé)將其轉(zhuǎn)換為 onEventName 形式的 prop,運行時通過 addEventListener 實際注冊。
幾個關(guān)鍵認(rèn)知:
mouseenter/mouseleave優(yōu)于mouseover/mouseout(不冒泡,性能更好)focusin/focusout是父元素感知子元素焦點的正確方式- 中文輸入必須處理
compositionstart/end,否則@input會在選字中間觸發(fā) @dragover.prevent是@drop能觸發(fā)的前提條件Pointer Events是未來趨勢,統(tǒng)一了鼠標(biāo)、觸控、筆的處理@scroll.passive是長列表滾動性能的關(guān)鍵修飾符
到此這篇關(guān)于Vue事件綁定完全指南之官方文檔未詳述的事件大全的文章就介紹到這了,更多相關(guān)Vue事件綁定完全指南內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Vue中點擊組件外關(guān)閉組件的實現(xiàn)方法
下面小編就為大家分享一篇基于Vue中點擊組件外關(guān)閉組件的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03
Vue3?使用Element?Plus表格單選帶checkbox功能
這篇文章主要介紹了Vue3?使用Element?Plus表格單選帶checkbox,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11
Vue通過字符串關(guān)鍵字符實現(xiàn)動態(tài)渲染input輸入框
這篇文章主要為大家詳細(xì)介紹了Vue如何通過字符串關(guān)鍵字符實現(xiàn)動態(tài)渲染input輸入框。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-12-12
詳解VUE-地區(qū)選擇器(V-Distpicker)組件使用心得
這篇文章主要介紹了詳解VUE-地區(qū)選擇器(V-Distpicker)組件使用心得,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05
Vue3中關(guān)于ref和reactive的區(qū)別分析
這篇文章主要介紹了vue3關(guān)于ref和reactive的區(qū)別分析,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-06-06
vue3使用Element-plus的el-pagination分頁組件時無法顯示中文
本文主要介紹了vue3使用Element-plus的el-pagination分頁組件時無法顯示中文,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12
解決element-ui的table表格控件表頭與內(nèi)容列不對齊問題
這篇文章主要介紹了解決element-ui的table表格控件表頭與內(nèi)容列不對齊問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
Vue箭頭函數(shù)與普通函數(shù)的正確使用及說明
文章解析Vue項目中箭頭函數(shù)與普通函數(shù)的this指向差異,指出90%錯誤源于誤用函數(shù)類型,提供Vue2/3場景下的使用邊界指南,強調(diào)需根據(jù)是否需要訪問Vue實例數(shù)據(jù)選擇函數(shù)類型,并給出1個判斷標(biāo)準(zhǔn)幫助開發(fā)者避免this相關(guān)錯誤2025-09-09

