HTMLAudioElement sound delay on keyboard clicks
SFC

Consider using Single File Components instead of the declarative syntax you are using right now. It removes a lot of the headache of dealing with the this keyword, and removes the necessity of having to deal with handlers. See the documentation for more information.

Life cycle hooks

Vue has a couple of life cycle hooks. You are currently using two of them. However, your code currently only works, because your html is not part of the component you just wrote. The destroyed life cycle hook is called after everything has been torn down, so there would be no html element to remove the handler from. You should be using the beforeDestroy hook instead. See this lifecycle diagram for more information.

Internal data

Your sound filenames should be internal data of your component, not some random variables outside it. They should also have descriptive names.

Sound playback delay

You are experiencing playback delay, because you load the sounds when you want to play them, instead of pre-loading them. You have two ways of dealing with this problem. If your sound file names are hardcoded, you can simply use the data initialisation function to create HTMLAudioElement s you can then later start or stop. See mdn for more information.

data () {
  return {
    sounds: {
      enter: new Audio('sound1.wav'),
      whatevercode12is: new Audio('sound2.mp3')
    }
  }
}


If you pass these sounds as properties, you need to be a bit more clever about it. You can use the created lifecycle hook to fill the sounds object like we created above, but would instead be initialised as an empty object, or you could put a watcher on the property with the immediate flag on true, and fill the sounds object as needed.

In either case you must play and immediately pause them once so they are downloaded. Then you can look them up and play them whenever you like:

this.playSound('enter')


and

playSound (soundName) {
  const playableSound = this.sounds[soundName];

  if (!playableSound) {
    throw new Error(`Called 'playSound' with unknown identifier [${soundName}]`);
  }

  playableSound.play();
}


Implementing it all

When you implement all that, you will end up with something like this:

&lt;template&gt;
  &lt;div id="app"&gt;
    &lt;input v-on:keydown.prevent="onKeyDown" value="Just focus me and press keys" /&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name: "App",
  data() {
    return {
      sounds: {
        enter: new Audio(
          "http://www.pacdv.com/sounds/miscellaneous_sounds/air_blower_1.wav"
        ),
        shift: new Audio(
          "http://www.pacdv.com/sounds/miscellaneous_sounds/bottle_pop_1.wav"
        )
      }
    };
  },

  created() {
    for (const sound of Object.values(this.sounds)) {
      // This makes sure the sounds are loaded, but not played
      sound.play().then(() =&gt; {
        sound.pause();
      });
    }
  },

  methods: {
    playSound(soundName) {
      const playableSound = this.sounds[soundName];

      if (!playableSound) {
        throw new Error(
          `Called 'playSound' with unknown identifier [${soundName}]`
        );
      }

      if (!playableSound.paused) {
        // The previous sound is playing. We could reset the current sound with
        // playableSound.currentTime = 0
        // but we probably don't want to cut off that sound, so lets make a copy of the
        // sound and dereference the previous one
        this.sounds[soundName] = new Audio(playableSound.src);
      }

      this.sounds[soundName].play();
    },

    onKeyDown(e) {
      switch (e.keyCode) {
        case 13:
          return this.playSound("enter");
        case 16:
          return this.playSound("shift");
        default:
          // Do nothing
          break;
      }
    }
  }
};
&lt;/script&gt;