Vue 怎么一次绑定点击和回车事件?

经常需要给某个元素同时绑定点击和回车事件:

<div
    class="custom-button"
    @click="handler"
    @keypress.enter="handler"
    tabindex="0"
>click me</div>

能不能封装起来?

如果通过自定义指令实现,TypeScript / Volar 支持会不会不太好?


补充说明:

  • custom-button 只是一个举例,因此仅仅封装 <CustomButton /> 不是我需要的解决方案
  • 封装更泛化的组件比如 <Enterable /> 语义上不太符合直觉
  • 指令在 Volar 中可以拿到类型提示,但有一些问题:

    • 不知道为什么指令名本身不能补全
    • 自定义指令 v-click-enter 不能享受 v-on 中直接写表达式的便利
      v-click-enter="addItem(value)" 是不行的,要写 v-click-enter="() => addItem(value)"
  • 我印象中 Vue 2 可以自定义新的全局事件,但是 Vue 3 似乎不再支持了,大家有没有相关的资料呢?
阅读 3.2k
5 个回答

可以通过封装一个Vue组件来实现这个功能。这样做的好处是,不仅可以让代码更加模块化,而且能够保持对TypeScript和Volar的良好支持。下面是一个示例实现:

<!-- CustomButton.vue -->
<template>
  <div
    class="custom-button"
    @click="handleClick"
    @keypress.enter="handleClick"
    tabindex="0"
  >
    <slot></slot>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'CustomButton',
  methods: {
    handleClick(event: MouseEvent | KeyboardEvent) {
      this.$emit('action', event);
    },
  },
});
</script>

<style scoped>
.custom-button {
  /* 在此处添加自定义样式 */
}
</style>

在这个示例中,我们创建了一个名为CustomButton的Vue组件,它同时绑定了点击事件和回车键的keypress事件。当其中任意一个事件触发时,组件会触发一个名为action的自定义事件,并将原始事件对象作为参数传递。

要使用这个组件,只需在父组件中引入并使用它:

<!-- ParentComponent.vue -->
<template>
  <custom-button @action="handler">Click me</custom-button>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import CustomButton from './CustomButton.vue';

export default defineComponent({
  name: 'ParentComponent',
  components: {
    CustomButton,
  },
  methods: {
    handler(event: MouseEvent | KeyboardEvent) {
      console.log('Clicked or pressed enter', event);
    },
  },
});
</script>

这样,可以在父组件中使用CustomButton组件,并通过监听action事件来处理点击或回车事件。TypeScript和Volar的支持也能够得到很好的保障。

其实使用form表单就可以了,表单的submit事件,既可以是点击事件出发,也可以是回车来触发,如果多个地方都需要支持回车事件,建议就直接使用form表单,也就不用给每个输入框去加回车事件了

在 Vue 中,可以使用 @keyup.enter 和 @click 事件来实现一次绑定点击和回车事件。你这段代码是可以封装的,如下image.png

目前还是用了自定义指令来解决

import { ObjectDirective } from 'vue'

export type ClickEnterEvent = (event: MouseEvent | KeyboardEvent) => void

const directive: ObjectDirective<HTMLElement, ClickEnterEvent> = {
    mounted: (el, binding) => {
        el.tabIndex = 0
        el.addEventListener('keypress', event => {
            if (event.key === 'Enter') binding.value(event)
        })
        el.addEventListener('click', binding.value)
    }
}

export default directive
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题