I recently had to add some support for global key shortcuts in a Vue application I am working on. Vue has built-in support for listening to keys when you are in an input element. What is not supported directly are global shortcuts. For instance, if I am viewing an email in Gmail, I can hit 'a' to answer that email.
To accomplish this in Vue with either need to use low-level JavaScript event listeners or a plugin, like vue-shortkey. The approaches are not actually that different since vue-shortkey is, not surprisingly, just wrapping event listeners. It is straight forward to write your own event listener in a component so I didn't see a huge amount of value in using a plugin. There are a few blog posts covering event listeners in Vue already, but I am going to take a stab a showing a more complete example here, including how to test the component.
Implementing
Let's say we wanted to create a component that displays a message whenever the escape key is pressed.
Our Template block:
<div>{% raw %}{{ message }}{% endraw %}</div>
Our Script block (Typescript):
import Vue from "vue";
export default Vue.component("Demo", {
created() {
window.addEventListener("keydown", this.escapeListener);
},
// make sure you remove the listener when the component is no longer visible
destroyed() {
window.removeEventListener("keydown", this.escapeListener);
},
data: function() {
return {
message: ""
};
},
methods: {
escapeListener(event: KeyboardEvent) {
if (event.key === "Escape") {
this.message = "Escape has been pressed";
}
}
}
});
If you prefer to use class syntax, change the script block to the following:
export default class Demo extends Vue {
private message = "";
private created() {
window.addEventListener("keydown", this.escapeListener);
}
private destroyed() {
window.removeEventListener("keydown", this.escapeListener);
}
private escapeListener(event: KeyboardEvent) {
if (event.key === "Escape") {
this.message = "Escape has been pressed";
}
}
}
Testing
This is all well and good, but it was not immediately clear how you test this behavior. After a few false starts, I stumbled upon a Github issue thread with the solution.
The magic I was missing was to use the Vue testing utils attachToDocument
option when mounting or shallow mounting the component under test. Once we attach our component to a document, we can use wrapper.trigger
to simulate our keypresses.
describe("Demo.vue", function() {
it("Displays a message when escape is pressed", function() {
const wrapper = shallowMount(Demo, { attachToDocument: true });
// the browser will add 'key' to the event,
// but when testing we need to add it manually
wrapper.trigger("keydown.esc", { key: "Escape" });
expect(wrapper.text()).to.include("Escape has been pressed");
// always make sure to destroy when using attachToDocument
wrapper.destroy();
});
});
And that is it, a straightforward way to test-drive our global shortcuts as we add them to our component.
Back to Explore Focused Lab