前端拾遗

123 阅读3分钟

封闭开发了一段时间重感冒了,本来应该整理为几篇文章,康复后发现细节已淡忘,记录为几个不同的片段吧

e.preventDefault()

背景:可模拟ant-design的select组件,在输入框有值显示下拉选择列表的基础上,当输入框为空的时候,显示10条之前的搜索历史记录列表

image.png 如果在Input组件的onBlur方法中,让下拉列表弹窗消失,弹窗里的任何点击事件都失效,包括删除按钮的点击事件和点击列表项。所以一开始写了一个useHook,即排除弹窗区域,点击弹窗外的任何地方,弹窗消失,在首页没有任何问题

/**
 * 自定义钩子:点击页面任何位置时触发回调函数
 * @param onClickAway - 点击页面任何位置时需要执行的回调函数
 * @param ref - React 引用对象,指向需要排除点击事件的 DOM 元素
 */
const useClickAnywhere = (onClickAway: () => void, ref: RefObject<HTMLElement>): void => {
  useEffect(() => {
    // 点击事件处理函数
    const handleClickOutside = (event: MouseEvent): void => {
      if (ref.current && !ref.current.contains(event.target as Node)) {
        onClickAway();
      }
    };

    // 绑定点击事件
    document.addEventListener('mousedown', handleClickOutside);

    // 组件卸载时移除事件监听
    return (): void => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [onClickAway, ref]);
};

export default useClickAnywhere;

可是子域嵌的Iframe,无法监听Iframe的点击事件, 导致子域弹窗一直尴尬的在那儿。和其中一位子域研发沟通后,他给我传了click事件,message监听到之后,处理弹窗消失。但是每个子域都需要这样做,每个子域研发不同,有点麻烦,e.preventDefault()出现了!!

e.preventDefault() 可以阻止某些特定的默认行为,但并不能阻止所有事件的触发。

  • e.preventDefault() 可以用于阻止 onPressEnter 事件的默认行为,例如在表单中按下回车键时阻止表单提交。
  • e.preventDefault() 可以用于阻止 onBlur 事件的默认行为,例如在某些情况下阻止输入框失去焦点。

所以只要在列表的最外层元素上加上onMouseDown={(e: React.MouseEvent<HTMLDivElement>) => e.preventDefault()}这段代码,就可以实现点击弹窗区域,弹窗不消失,点击弹窗之后,触发onBlur,弹窗消失

举个例子,假设我们有一个输入框和一个按钮,当点击按钮时,阻止输入框失去焦点(阻止 onBlur 事件):

import React, { useRef } from 'react';
import { Input, Button } from 'antd';

const PreventBlurExample = () => {
  const inputRef = useRef(null);

  const handleMouseDown = (e) => {
    e.preventDefault(); // 阻止按钮点击时输入框失去焦点
  };

  return (
    <div>
      <Input ref={inputRef} placeholder="Click the button to prevent blur" />
      <Button onMouseDown={handleMouseDown}>Prevent Blur</Button>
    </div>
  );
};

export default PreventBlurExample;

在这个例子中,当点击按钮时,e.preventDefault() 阻止了 onMouseDown 事件的默认行为,从而阻止了输入框的 onBlur 事件。

pointer-events: none

背景:react项目,div包了一个svg元素,div上有个onClick点击事件,本地调试没有问题,pre环境发现点击svg的边缘可以触发onClick,点击svg没有反应。

一开始的解决方法是把svg改为了Img,后来大佬推荐了pointer-events: none;

当时时间紧迫且别人维护的代码又臭又长,没太研究具体原因

猜测可能的原因:

  1. 事件传播问题:SVG元素可能会阻止事件传播到其父元素(即div),尤其是当SVG内部有自己的一些事件处理逻辑时。即事件在SVG元素上被阻止或中断了。
  2. SVG默认行为:一些SVG元素可能会有自己的默认行为,阻止了事件的传播或者处理。

解释

CSS pointer-events 属性

  • 在CSS中,pointer-events: none; 的作用是禁用元素的鼠标事件。这意味着,当你把鼠标移动到该元素上时,它不会响应任何鼠标事件(如点击、悬停等)。
    • pointer-events: none; 属性使得 SVG 元素不会拦截点击事件。这样,当你点击 SVG 元素时,事件会直接传递给它的父元素(即 div)。