Front-End프로그래밍

[Vue.js] @contextmenu.prevent 사용 방법 예제 총정리

@contextmenu.preventVue.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)

error: Content is protected !!