우클릭 메뉴 플러그인
우클릭 메뉴 · contextMenuPlugin
셀 우클릭으로 업무 메뉴를 열고 클릭한 셀의 행 키·필드와 현재 그리드를 사용자 action에 전달합니다.
설치 함수: contextMenuPlugin(config) · 해제 이름: contextMenu
설정 속성 · 기본값
필수값은 해당 입력에서 반드시 제공하는 값입니다. 조건부 필수값은 설명에 적힌 기능을 사용할 때 필요합니다. 표시가 없는 옵션은 생략할 수 있으며 기본값을 사용합니다. 빈 문자열·누락과 0·false를 혼동하지 마세요.
| 설정 | 기본값 | 설명 |
|---|---|---|
items | 원복·Undo 항목 | {label,action} 배열입니다. 생략하면 기본 메뉴를 사용하고 []면 항목이 없습니다. |
items[].label 조건부 필수값 | 사용자 지정 | 메뉴 텍스트입니다. HTML로 실행하지 않습니다. 사용자 items 항목을 추가하면 메뉴명을 지정합니다. items를 생략하면 기본 메뉴를 사용합니다. |
items[].action 조건부 필수값 | 사용자 함수 | action(grid,active)을 호출합니다. active는 {id,field}입니다. 필요하면 grid.model.getRow(active.id)로 복사된 행을 읽습니다. 사용자 items 항목을 추가하면 실행할 함수를 지정합니다. |
사용 순서
- 메뉴 label과 action을 선언합니다.
- 셀을 우클릭하면 해당 셀을 선택하고 브라우저 메뉴 대신 사용자 메뉴를 표시합니다.
- 항목 실행 뒤 메뉴를 닫고 그리드로 포커스를 돌립니다. 위/아래 방향키로 이동하고 Escape로 닫습니다.
연결 API
| 호출 | 동작 |
|---|---|
grid.install(contextMenuPlugin({items})) | 사용자 action을 포함한 메뉴를 설치합니다. 필수값 |
grid.uninstall("contextMenu") | 열린 메뉴를 닫고 플러그인을 해제합니다. 별도 공개 open API는 없습니다. 필수값 |
설치 · 해제 · Vue 3 수명주기
생성 시 plugins에 등록하거나, 아직 설치하지 않은 인스턴스에서 grid.install을 호출합니다. 같은 name은 중복 설치할 수 없습니다. 설정에 쓰는 데이터·함수는 아래 전체 예제 소스를 참고하세요.
grid.install(contextMenuPlugin({
items: [
{
label: '첫 행 수량 변경',
action: (g) => g.updateCells([{ id: 1, field: 'qty', value: 8 }]),
},
{ label: '변경 원복', action: (g) => g.revertChanges() },
],
}));
grid.uninstall('contextMenu'); // 플러그인 해제
// Vue 3 컴포넌트가 종료될 때
onBeforeUnmount(() => grid.destroy());열린 메뉴를 제거하고 그리드 contextmenu 및 document pointerdown 리스너를 해제합니다.
관련 이벤트
- selectionchange
- datachange (action이 데이터를 바꾸는 경우)
이벤트 구독은 grid.on(name, (detail, grid) => {})를 사용합니다. 해제 함수 또는 grid.off로 구독을 정리하세요.
실행 예제 · 실제 원본
아래 소스는 examples/features/context-menu.js와 Vue 원본입니다. 해당 예제 경로를 기준으로 import하며, 행 데이터는 별도 파일을 함께 사용합니다.
JavaScript 예제 실행 ↗ · Vue 3 예제 실행 ↗ · 행 데이터 원본
JavaScript 전체 소스 · context-menu.js
import { ZixoGrid, contextMenuPlugin } from '../../src/index.js';
import { rows } from './context-menu.data.js';
const host = document.querySelector('#grid'),
report = document.querySelector('#report');
const options = {
rowKey: 'id',
height: 360,
rows: rows,
columns: [
{ field: 'name', title: '주문', width: 240 },
{ field: 'qty', title: '수량', type: 'number', parse: Number },
{ field: 'price', title: '단가', type: 'number', parse: Number },
],
plugins: [
contextMenuPlugin({
items: [
{
label: '첫 행 수량 변경',
action: (g) => g.updateCells([{ id: 1, field: 'qty', value: 8 }]),
},
{ label: '변경 원복', action: (g) => g.revertChanges() },
],
}),
],
};
const grid = new ZixoGrid(host, options);
window.addEventListener('pagehide', () => grid.destroy(), { once: true });
grid.on(
'validationerror',
(detail) => (report.textContent = detail.error.message),
);
report.textContent =
'셀 우클릭으로 사용자 메뉴를 엽니다. 방향키 이동과 Escape 닫기를 지원합니다.';
Vue 3 전체 소스 · vue-context-menu.vue
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { ZixoGrid, contextMenuPlugin } from '../../src/index.js';
import { rows } from './context-menu.data.js';
// Instance and DOM belong to this component, never to window or a global ID.
const gridHost = ref(null);
const message = ref('');
let grid;
let alive = true;
onMounted(() => {
const options = {
rowKey: 'id',
height: 360,
rows: rows,
columns: [
{ field: 'name', title: '주문', width: 240 },
{ field: 'qty', title: '수량', type: 'number', parse: Number },
{ field: 'price', title: '단가', type: 'number', parse: Number },
],
plugins: [
contextMenuPlugin({
items: [
{
label: '첫 행 수량 변경',
action: (g) => g.updateCells([{ id: 1, field: 'qty', value: 8 }]),
},
{ label: '변경 원복', action: (g) => g.revertChanges() },
],
}),
],
};
grid = new ZixoGrid(gridHost.value, options);
grid.on(
'validationerror',
(detail) => (message.value = detail.error.message),
);
message.value =
'셀 우클릭으로 사용자 메뉴를 엽니다. 방향키 이동과 Escape 닫기를 지원합니다.';
});
onBeforeUnmount(() => {
alive = false;
grid?.destroy(); // Cancels grid requests, removes events and releases plugins.
grid = undefined;
});
defineExpose({ getGrid: () => grid });
</script>
<template>
<main>
<h1>우클릭 Context Menu</h1>
<div ref="gridHost" class="vue-grid-host"></div>
<div class="notes result" aria-live="polite">{{ message }}</div>
</main>
</template>
제약 사항 · 주의할 동작
- 셀 컨텍스트 메뉴입니다. 헤더 메뉴는 columnToolsPlugin을 사용합니다.
- action은 직접 호출되며 비동기 완료·예외의 UI 처리는 사용자 action에서 담당합니다.
- 업무 action의 권한 확인은 필요에 따라 별도로 구현합니다.
연결 기능 메뉴
우클릭 Context Menu · 범위 선택 · 클립보드 · Fill · 행 추가 · 수정 · 삭제 · 원복