hotkeys-js icon indicating copy to clipboard operation
hotkeys-js copied to clipboard

Vuejs version of Hotkeys

Open rutvij2292 opened this issue 4 years ago • 7 comments

Hello,

Thanks for a wonderful keyboard binding library, I was trying to integrate this library in my vue project I and can't.

Does any one tried to implement in their vuejs project? If someone tried, guide me how to integrate it, that would be amazing.

Thanks! Rutvij

rutvij2292 avatar Oct 14 '19 06:10 rutvij2292

Mind sharing more about what you're trying to achieve? It would help if you can give us more insight into how deep do you want the lib to integrate with your project.

I'm currently using this lib in my project, but I'm not doing anything too complicated and it's just sitting on top of what I have. If that's what you want, feel free to check out the file where I'm using it.

Cheers!

japorized avatar Dec 18 '19 22:12 japorized

You can use the hotkeys function directly to bind and unbind hotkeys. I made an example of using it with Vue on CodeSandbox, but essentially you can use the mounted and beforeDestroy methods to bind a hotkey whenever a component is mounted on the screen (this assumes there's only one instance of this component mounted at a time):

import hotkeys from "hotkeys-js";

export default {
  name: "ComponentWithHotkey",
  mounted() {
    hotkeys("a", () => this.hotkeyPressed());
  },
  beforeDestroy() {
    hotkeys.unbind("a");
  },
  methods: {
    hotkeyPressed() {
      this.$emit("increment");
    }
  }
};

jennings avatar Jan 16 '20 20:01 jennings

The problem is that the imported hotkeys is a singleton, so you have to manually unbind all the bindings you made on a given component (cf. @jennings example). If you don't, Hotkeys will hold onto a reference of your component; it won't be freed from memory, and you'll rebind the same keys when the component is mounted again. It will build up the memory, the CPU usage, and may introduce bugs.

Unfortunately, if re-binding the same keys on a new component doesn't introduce bugs, you'll have a memory leak that will be hard to track.

@jaywcjlove A way to fix this would be to let users instantiate and manage their own Hotkeys instance(s) themselves, if that's possible. Or, without rewriting much, you could warn users if they're re-binding the same keys via a console.warn (maybe activated only via a debug flag to avoid spam)

scambier avatar Apr 23 '20 17:04 scambier

@scambier Even if you had a separate instance of the hotkeys object, you'd still need a clean-up step that gets called when the component is being unmounted. I'm not sure if having a separate instance of hotkeys would solve the resource leak.

// hypothetical API for creating a hotkeys instance
import { makeHotkeysInstance } from "hotkeys-js";

export default {
  name: "ComponentWithHotkey",
  mounted() {
    this.hotkeys = makeHotkeysInstance();
    this.hotkeys("a", () => this.hotkeyPressed());
  },
  beforeDestroy() {
    // still requires cleanup or else the arrow function
    // will remain bound to the window's keydown event
    this.hotkeys.destroy();
  },
  ...
};

jennings avatar May 27 '20 22:05 jennings

You're right, I'm not sure what I had in mind. But your example shows a nice way to do it: you don't have to keep an up-to-date list of unbind() calls, as a single call to this.hotkeys.destroy() could do the job. That'd be cleaner and less error-prone IMO

scambier avatar May 28 '20 05:05 scambier

Sorry for responding to an old thread, but I took a different route by binding hotkeys to the Vue instance prototype. And only clean up using the scope functions in my components. This way the cleanup is simple and hotkeys is called only once.

Before calling new Vue() attach hotkeys: Vue.prototype.$keys = hotkeys.noConflict(true)

And in my components:

export default {
    data: {
        hotKeyScope: 'some-usefull-name'
    },
    created() {
         this.$keys('enter', this.hotKeyScope, () => { /*...*/ })
    },
    beforeDestroy() {
        this.$keys.deleteScope(this.hotKeyScope);
    }
}

I've not tested all use/edge-cases, but worked well enough in my apps. My guess is that if you have multiple competing scopes on the same page, you'll have to manage these yourself.

renzo-s avatar Jul 06 '20 14:07 renzo-s

Hi there, I made a composition-api version of this and published as vue-use-hotkeys on npm. Try it out if interested.

Mitscherlich avatar Jan 23 '22 04:01 Mitscherlich