[Vue.js] @contextmenu.prevent 사용 방법 예제 총정리
@contextmenu.prevent
는 Vue.js에서 사용하는 디렉티브입니다.
의미 분석
@contextmenu
:
이는 DOM 요소에서 마우스 오른쪽 클릭(컨텍스트 메뉴) 이벤트를 감지하는 Vue 이벤트 리스너입니다.
즉, 사용자가 해당 요소에서 오른쪽 클릭했을 때 실행됩니다..prevent
:
이는 이벤트의 기본 동작을 막는다는 뜻입니다.
여기서는 브라우저의 기본 오른쪽 클릭 메뉴가 뜨지 않도록 차단합니다.
예시
<div class="" @contextmenu.prevent>
오른쪽 클릭 메뉴가 열리지 않음
</div>
이렇게 하면, 사용자가 해당 <div>
위에서 마우스 오른쪽 버튼을 눌러도 브라우저의 기본 컨텍스트 메뉴가 나타나지 않습니다.
참고: .prevent
없이 쓰면?
<div @contextmenu="onRightClick">
이렇게 하면 오른쪽 클릭 이벤트를 감지하지만 “기본 동작(컨텍스트 메뉴 열림)”은 그대로 발생합니다. 메뉴를 막으려면 event.preventDefault()
를 수동으로 호출해야 합니다.
🛠 응용
<div @contextmenu.prevent="openCustomMenu($event)">
커스텀 메뉴 띄우기
</div>
이렇게 하면 기본 메뉴는 막고, 사용자 정의 메뉴를 열 수 있습니다.
커스텀 오른쪽 클릭 메뉴 구현 예제(Vue 3 + Composition API)
CustomContextMenu.vue
<template>
<div v-if="visible" :style="menuStyle" class="context-menu">
<ul>
<li @click="onAction('복사')">복사</li>
<li @click="onAction('붙여넣기')">붙여넣기</li>
<li @click="onAction('삭제')">삭제</li>
</ul>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const props = defineProps(['x', 'y', 'visible'])
const emit = defineEmits(['action'])
function onAction(action) {
emit('action', action)
}
const menuStyle = computed(() => ({
position: 'absolute',
top: props.y + 'px',
left: props.x + 'px',
backgroundColor: '#fff',
border: '1px solid #ccc',
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
zIndex: 1000,
padding: '4px 0',
}))
</script>
<style scoped>
.context-menu ul {
list-style: none;
margin: 0;
padding: 0;
}
.context-menu li {
padding: 8px 16px;
cursor: pointer;
}
.context-menu li:hover {
background-color: #f0f0f0;
}
</style>
App.vue
<template>
<div @contextmenu.prevent="showMenu($event)" style="height: 100vh; background-color: #f9f9f9;">
<h1>오른쪽 클릭해서 메뉴 열기</h1>
<CustomContextMenu
:x="menuX"
:y="menuY"
:visible="menuVisible"
@action="handleMenuAction"
/>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import CustomContextMenu from './CustomContextMenu.vue'
const menuVisible = ref(false)
const menuX = ref(0)
const menuY = ref(0)
function showMenu(event) {
menuX.value = event.pageX
menuY.value = event.pageY
menuVisible.value = true
}
function handleMenuAction(action) {
alert(`"${action}" 메뉴가 선택되었습니다.`)
menuVisible.value = false
}
// 클릭하면 메뉴 닫기
onMounted(() => {
window.addEventListener('click', () => {
menuVisible.value = false
})
})
</script>
기능 요약
- 오른쪽 클릭하면 기본 브라우저 메뉴는 차단됨 (
@contextmenu.prevent
) - 클릭한 위치에 맞춰 커스텀 메뉴가 떠서 다양한 작업을 선택할 수 있음
- 메뉴 바깥을 클릭하면 자동으로 사라짐
Vue 커스텀 오른쪽 클릭 메뉴 (동적+ 아이콘 추가)
메뉴 항목을 배열로 전달받아 동적으로 렌더링, 각 항목에 아이콘(Font Awesome 또는 Emoji) 표시 가능
CustomContextMenu.vue
(동적 메뉴 + 아이콘)
<template>
<div v-if="visible" :style="menuStyle" class="context-menu">
<ul>
<li v-for="item in items" :key="item.label" @click="onAction(item)">
<span class="icon">{{ item.icon }}</span>
{{ item.label }}
</li>
</ul>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
x: Number,
y: Number,
visible: Boolean,
items: Array, // [{ label: '복사', icon: '📋' }, ...]
})
const emit = defineEmits(['action'])
function onAction(item) {
emit('action', item)
}
const menuStyle = computed(() => ({
position: 'absolute',
top: props.y + 'px',
left: props.x + 'px',
backgroundColor: '#fff',
border: '1px solid #ccc',
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
zIndex: 1000,
padding: '4px 0',
}))
</script>
<style scoped>
.context-menu ul {
list-style: none;
margin: 0;
padding: 0;
}
.context-menu li {
padding: 8px 16px;
cursor: pointer;
display: flex;
align-items: center;
}
.context-menu li:hover {
background-color: #f0f0f0;
}
.icon {
margin-right: 8px;
width: 1.2em;
text-align: center;
}
</style>
App.vue
(동적 항목 + 아이콘 사용)
<template>
<div @contextmenu.prevent="showMenu($event)" style="height: 100vh; background-color: #f9f9f9;">
<h1>오른쪽 클릭해서 커스텀 메뉴 열기</h1>
<CustomContextMenu
:x="menuX"
:y="menuY"
:visible="menuVisible"
:items="menuItems"
@action="handleMenuAction"
/>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import CustomContextMenu from './CustomContextMenu.vue'
const menuVisible = ref(false)
const menuX = ref(0)
const menuY = ref(0)
const menuItems = ref([
{ label: '복사', icon: '📋' },
{ label: '붙여넣기', icon: '📥' },
{ label: '삭제', icon: '🗑️' },
])
function showMenu(event) {
menuX.value = event.pageX
menuY.value = event.pageY
menuVisible.value = true
}
function handleMenuAction(item) {
alert(`"${item.label}" 메뉴가 선택되었습니다.`)
menuVisible.value = false
}
onMounted(() => {
window.addEventListener('click', () => {
menuVisible.value = false
})
})
</script>
확장 아이디어
- ✅ 아이콘을 Emoji 대신 Font Awesome 사용 가능
- 🌙 다크 모드 지원 (
prefers-color-scheme
) - ⌨️ 키보드 네비게이션
- 🧠 항목별 권한/비활성화 상태 (
disabled: true
)