For anyone who wanders here from google, in Vue 2...
<div @keydown.esc="something_in_your_methods"></div>
The secret for making keydown
events work on divs and other non-focusable elements is to add a tabindex
attribute:
<div tabindex="0"
@keydown.left="previousImage"
@keydown.right="nextImage" />
Now the div has become a focusable element and the key events will be triggered.
Here is more info on focusable elements and tabindex
What I did was go for a mixin.
The mixin in a file called close.js
export default {
created() {
let that = this;
document.addEventListener('keyup', function (evt) {
if (evt.keyCode === 27) {
that.close();
}
});
},
};
Import and use it in the desired component
import closeMixin from './../../mixins/close.js';
export default {
mixins: [closeMixin],
props: [],
computed: {}
methods: {
close(){
// closing logic
}
}
}
You can't. Key events are dispatched from the body tag and Vue can't be mounted to the <body>
tag.
]
You'll have to set up your own event listener.
(image source & more info at When VueJS Can't Help You)
3 things to make sure of on the main element:
Here is how I usually manage my modals:
<div ref="modal" @keyup.esc="close" tabindex="-1">
<!-- Modal content -->
</div>
mounted() {
this.$refs.modal.focus();
}
In my case, I created a directive, v-esc.ts. (※ This is Vue3 directive writing way)
import { Directive } from 'vue'
const directive: Directive = {
beforeMount(el, binding) {
el._keydownCallback = (event) => {
if (event.key === 'Escape') {
binding.value()
}
}
document.addEventListener('keydown', el._keydownCallback)
},
unmounted(el, binding) {
document.removeEventListener('keydown', el._keydownCallback)
delete el._keydownCallback
}
}
export const esc = { esc: directive }
Then I can use it in any component like this. (NOTE: you must pass a function param to v-esc, because the param executed as binding.value() in the directive)
<template>
<img
@click.prevent="close"
v-esc="close"
src="@/assets/icons/close.svg"
/>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { esc } from '@/common/directives/v-esc'
export default defineComponent({
name: 'nitCloseButton',
...
methods: {
close() {
this.$emit('close')
}
},
directives: {
...esc
}
})
</script>
P.S One month after, I also need arrow left and arrow right keys. So, I've made this directive more general like this.
import { Directive } from 'vue'
const directive: Directive = {
beforeMount(el, binding) {
el._keydownCallback = event => {
console.log('keydown', event.key)
if (event.key === binding.arg) {
binding.value()
}
}
document.addEventListener('keydown', el._keydownCallback)
},
unmounted(el, binding) {
document.removeEventListener('keydown', el._keydownCallback)
delete el._keydownCallback
}
}
export const keydown = { keydown: directive }
You can detect any key's keydown by passing keyname as binding.args (v-keydown:{keyName} like below)
<button
v-keydown:ArrowLeft="moveToPreviousPage"
class="controller-button lo-center"
@click="moveToPreviousPage"
>
<arrow-icon :rotation="180" />
</button>
<button
v-keydown:ArrowRight="moveToNextPage"
class="controller-button lo-center"
@click="moveToNextPage"
export default defineComponent({
name: 'componentName',
directives: {
...keydown
}
...
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With