Today we are going to create our context menu with VueJS from scratch, with traditional "Hello World" example.
Create fresh Vue Project
Let's start by creating new project and running the application.
The first you have to do is to install the Vue CLI on your computer
To create a new project, run:
create <enter the app name>
More about Vue cli, you can see here from their official docs.
It will generate new Project with following initial file structure:
- index.html
- src/App.vue
- src/main.js
- src/assets/logo.png
- src/components/HelloWorld.vue
Start Project
Now lets run our generated project by Vue CLI
cd <project-name>
npm install
npm run serve
The Vue Instance
We will open now App.vue there will be following code:
<div id="app">
<img width="25%" src="./assets/logo.png">
<HelloWorld/>
</div>
For now we can remove HelloWorld component and create new component named ContextMenu.vue
Open you ContextMenu.vue and add basic template
<div class="context-menu" ref="context" tabindex="0">
<slot></slot>
</div>
A bit about code
Slot will allow us to render components inside of our context menu, and tabIndex prop will focus element
Add Styles
<style>
.context-menu {
position: fixed;
background: white;
z-index: 999;
outline: none;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
cursor: pointer;
}
</style>
Now add some logic and full component Code
<template>
<div class="context-menu" v-show="show" :style="style" ref="context" tabindex="0" @blur="close">
<slot></slot>
</div>
</template>
<script>
import Vue from 'vue';
export default {
name: 'CmpContextMenu',
props: {
display: Boolean, // prop detect if we should show context menu
},
data() {
return {
left: 0, // left position
top: 0, // top position
show: false, // affect display of context menu
};
},
computed: {
// get position of context menu
style() {
return {
top: this.top + 'px',
left: this.left + 'px',
};
},
},
methods: {
// closes context menu
close() {
this.show = false;
this.left = 0;
this.top = 0;
},
open(evt) {
// updates position of context menu
this.left = evt.pageX || evt.clientX;
this.top = evt.pageY || evt.clientY;
// make element focused
// @ts-ignore
Vue.nextTick(() => this.$el.focus());
this.show = true;
},
},
};
</script>
<style>
.context-menu {
position: fixed;
background: white;
z-index: 999;
outline: none;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
cursor: pointer;
}
</style>
The code is self self explanatory explained open
method opens context menu, close
method closes the context menu, and computed propert styles
that will return position of context menu.
Usage
Now import your new component into App.vue, and start show your own context menu.
<div id="app">
<img width="25%" src="./assets/logo.png">
<context-menu :display="showContextMenu" ref="menu">
<ul>
<li> List item 1 </li>
<li> List item 2 </li>
</ul>
</context-menu>
<button @click='openContextMenu'>activate context menu</button>
</div>
<script>
import ContextMenu from './ContextMenu';
export default {
components: {
ContextMenu,
},
data() {
return { showContextMenu: false }
},
methods: {
openContextMenu(e) {
this.$refs.menu.open(e);
}
}
}
</script>
With a little edit you could create something looking like this:
Note
This is just a basic and really simple example how you could create context menu with as little code as possible.
As is almost always the case, you'll need to pick the approach that makes the most sense for your use-case.
Top comments (5)
what is the use of prop
display
in this?Thank you for this article. You need an edit. you should add pageYOffset when user scroll to down.
this.top = (evt.pageY || evt.clientY) - window.pageYOffset;
Great
thank you :)
Nice Tips ❤