前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >react 监听键盘事件 hook

react 监听键盘事件 hook

原创
作者头像
小鑫
发布2022-04-25 15:16:14
2.2K0
发布2022-04-25 15:16:14
举报
文章被收录于专栏:小鑫の随笔
代码语言:javascript
复制
import { useCallback, useEffect, MutableRefObject } from "react";

type keyType = KeyboardEvent["keyCode"] | KeyboardEvent["key"];
type keyFilter = keyType | Array<keyType>;
type EventHandler = (event: KeyboardEvent) => void;
type keyEvent = "keydown" | "keyup";
type BasicElement = HTMLElement | Element | Document | Window;
type TargetElement = BasicElement | MutableRefObject<null | undefined>;
type EventOptions = {
  events?: Array<keyEvent>;
  target?: TargetElement;
};

const modifierKey: any = {
  ctrl: (event: KeyboardEvent) => event.ctrlKey,
  shift: (event: KeyboardEvent) => event.shiftKey,
  alt: (event: KeyboardEvent) => event.altKey,
  meta: (event: KeyboardEvent) => event.metaKey
};

const defaultEvents: Array<keyEvent> = ["keydown"];

/**
 * 判断对象类型
 * @param obj 参数对象
 * @returns String
 */
function isType<T>(obj: T): string {
  return Object.prototype.toString
    .call(obj)
    .replace(/^\[object (.+)\]$/, "$1")
    .toLowerCase();
}

/**
 * 获取当前元素
 * @param target TargetElement
 * @param defaultElement 默认绑定的元素
 */
function getTargetElement(
  target?: TargetElement,
  defaultElement?: BasicElement
) {
  if (!target) {
    return defaultElement;
  }

  if ("current" in target) {
    return target.current;
  }

  return target;
}

/**
 * 按键是否激活
 * @param event 键盘事件
 * @param keyFilter 当前键
 */
const keyActivated = (event: KeyboardEvent, keyFilter: any) => {
  const type = isType(keyFilter);
  const { keyCode } = event;

  if (type === "number") {
    return keyCode == keyFilter;
  }

  const keyCodeArr = keyFilter.split(".");
  // 符合条件的长度
  let genLen = 0;
  // 组合键
  for (const key of keyCodeArr) {
    const genModifier = modifierKey[key];

    if ((genModifier && genModifier) || keyCode == key) {
      genLen++;
    }
  }

  return genLen === keyCodeArr.length;
};

/**
 * 键盘按下预处理方法
 * @param event 键盘事件
 * @param keyFilter 键码集
 */
const genKeyFormate = (event: KeyboardEvent, keyFilter: any) => {
  const type = isType(keyFilter);

  if (type === "string" || type === "number") {
    return keyActivated(event, keyFilter);
  }

  // 多个键
  if (type === "array") {
    return keyFilter.some((item: keyFilter) => keyActivated(event, item));
  }
};

/**
 * 监听键盘按下/松开
 * @param keyCode
 * @param eventHandler
 * @param options
 */
const useKeyPress = (
  keyCode: keyFilter,
  eventHandler?: EventHandler,
  options: EventOptions = {}
) => {
  const { target, events = defaultEvents } = options;

  const callbackHandler = useCallback(
    (event) => {
      if (genKeyFormate(event, keyCode)) {
        typeof eventHandler === "function" && eventHandler(event);
      }
    },
    [keyCode]
  );

  useEffect(() => {
    const el = getTargetElement(target, window)!;

    for (const eventName of events) {
      el.addEventListener(eventName, callbackHandler);
    }

    return () => {
      for (const eventName of events) {
        el.removeEventListener(eventName, callbackHandler);
      }
    };
  }, [keyCode, events, callbackHandler]);
};

export default useKeyPress;

使用方法

代码语言:javascript
复制
useKeyPress(["13", "108"], () => {
  console.log("按下了回车");
});

点击下方链接查看运行效果:

https://codesandbox.io/s/react-jiantingjianpanshijian-hook-oewt9?fontsize=14&hidenavigation=1&theme=dark

参数

参数

说明

类型

keyFilter

按键 code

keyType

EventHandler

事件回调函数

(event: KeyboardEvent) => void

options

可配置项

EventOptions

options

参数

说明

类型

events

触发事件

Array<keydown

target

DOM 节点或 Ref 对象

HTMLElement Element

git:https://github.com/isxiaoxin/front_end_wheel/tree/master/hooks/useKeyPress

首发自:react 监听键盘事件 hook - 小鑫の随笔

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用方法
  • 参数
  • options
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档