原来 document.activeElement 这么好用!

 咱平时写网页交互,总盯着那些 “大功能”,比如怎么做弹窗、怎么搞表单校验,却很少在意一个藏在 DOM 里的 “小透明”:document.activeElement

这玩意儿说穿了特简单:就是告诉你现在页面上 “用户正盯着操作的那个元素”。但你别小瞧它,之前我做项目时踩过好几个坑,最后发现,哦豁,用它一下就解决了!今天就跟你唠唠,这东西在实际场景里有多香,全是我踩坑总结的干货,特接地气~

先掰扯清楚:这玩意儿到底是啥?

其实不用讲复杂概念,你肯定遇过这种情况:比如你在输入框里打字,这时候输入框就是 “焦点元素”;按 Tab 键切到按钮上,按钮就成了焦点元素。而 document.activeElement 就是帮你 “抓包” 这个元素的 —— 你随时喊它一声,它就告诉你:“现在用户在跟哪个元素玩呢!”

就这么个小功能,能解决好多让用户 “想吐槽” 的问题,咱一个个说~

案例 1:填表单时,别让错误提示 “群魔乱舞”

你肯定有过这体验:填个注册表单,左边输手机号,右边邮箱还没填呢,俩输入框下面的错误提示全冒出来了,密密麻麻的看着就烦!

之前我做项目也踩过这坑,后来用 document.activeElement 改了下,瞬间清爽了。思路特简单:用户现在在输哪个框,就只校验哪个框,其他框的错误提示先藏起来。

比如表单里有手机号和邮箱俩输入框,代码可以这么写(咱别搞太复杂,看个意思就行):

// 给所有输入框加个“输入时校验”的监听
const inputs = document.querySelectorAll('input');
inputs.forEach(input => {
  input.addEventListener('input', () => {
    // 先把所有错误提示清空,别堆着
    document.querySelectorAll('.error').forEach(el => el.textContent = '');
    
    // 看看现在用户在输哪个框(这步就是核心!)
    const currentInput = document.activeElement;
    const errorEl = document.getElementById(`${currentInput.id}Error`);
    
    // 只校验当前正在输的框
    if (currentInput.id === 'phone') {
      if (!/^\d{11}$/.test(currentInput.value) && currentInput.value) {
        errorEl.textContent = '兄弟,手机号得11位啊!';
      }
    } else if (currentInput.id === 'email') {
      if (!/^[\w-]+@[a-zA-Z0-9]+\.[a-zA-Z]+$/.test(currentInput.value) && currentInput.value) {
        errorEl.textContent = '邮箱格式不对哦,比如xxx@xx.com';
      }
    }
  });
});

你看,这样用户输手机号时,就只提示手机号的问题,输邮箱时才管邮箱 —— 再也不会被一堆错误提示烦到了,体验立马上去了~

案例 2:关弹窗后,别让焦点 “迷路”

这事儿你绝对遇过:点开一个弹窗(比如填个信息的小窗口),输完内容关了弹窗,想继续按 Tab 键切回之前的按钮,结果按了半天没反应,低头一看 —— 焦点不知道跑哪儿去了,默认回到了页面最开头。

我之前做后台系统时,用户就吐槽过这个:“关了弹窗想接着操作,结果得重新找按钮,太麻烦了!” 后来用 document.activeElement 记一下焦点位置,问题就解决了。

思路超简单:打开弹窗前,先记一下 “用户当时在操作哪个元素”;关弹窗时,再把焦点送回去。代码大概长这样:

<!-- 打开弹窗的按钮 -->
<button id="openModalBtn">点开我看弹窗</button>
<!-- 弹窗 -->
<div id="modal" style="display: none;">
  <input type="text" placeholder="随便输点啥">
  <button id="closeModalBtn">关掉弹窗</button>
</div>
const openBtn = document.getElementById('openModalBtn');
const closeBtn = document.getElementById('closeModalBtn');
const modal = document.getElementById('modal');
let lastFocusedEl; // 存一下打开弹窗前的焦点,像记笔记似的

// 点开弹窗时:先记焦点,再让弹窗里的输入框“接棒”
openBtn.addEventListener('click', () => {
  lastFocusedEl = document.activeElement; // 记下来:用户之前在点这个按钮
  modal.style.display = 'block';
  // 让弹窗里的输入框获得焦点,用户不用再点一下
  modal.querySelector('input').focus();
});

// 关掉弹窗时:把焦点送回“老家”
closeBtn.addEventListener('click', () => {
  modal.style.display = 'none';
  lastFocusedEl?.focus(); // 比如回到之前的“打开弹窗”按钮
});

你试试就知道,关了弹窗再按 Tab,焦点还在原来的位置,不用重新找,爽多了~

案例 3:编辑器按快捷键没反应?可能是焦点跑了

我之前做过一个简单的富文本编辑器,加了个 “Ctrl+B 加粗” 的功能。结果测试时发现:有时候按 Ctrl+B 有用,有时候没用,整得我一头雾水。

后来查了半天,哦!原来是焦点的问题 —— 比如用户点了编辑器旁边的按钮,焦点跑到按钮上了,这时候按 Ctrl+B,编辑器根本 “收不到” 这个信号,自然没反应。

后来用 document.activeElement 加了个判断,问题秒解:只有当焦点在编辑器里时,Ctrl+B 才生效。代码也特简单:

<!-- 可编辑的编辑器区域 -->
<div id="editor" contenteditable="true" style="border: 1px solid #ccc; padding: 10px;">
  在这里输文字,按Ctrl+B加粗
</div>
<!-- 旁边的干扰按钮 -->
<button id="otherBtn">我是个没用的按钮</button>
const editor = document.getElementById('editor');

document.addEventListener('keydown', (e) => {
  // 判断两个条件:1. 按的是Ctrl+B;2. 焦点在编辑器里
  if (e.ctrlKey && e.key === 'b' && document.activeElement === editor) {
    e.preventDefault(); // 别让浏览器自己弹书签栏(懂的都懂)
    
    // 简单加粗逻辑:选中的文字包个<b>标签
    const selection = window.getSelection();
    if (selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      const boldEl = document.createElement('b');
      boldEl.appendChild(range.extractContents());
      range.insertNode(boldEl);
    }
  }
});

现在就稳了 —— 用户想加粗时,只要焦点在编辑器里,按 Ctrl+B 就管用;焦点跑出去了,按了也不瞎反应,不会误操作~

案例 4:防止重复提交?让焦点 “锁” 在按钮上

你肯定遇过这种情况:点了 “登录” 按钮,网络有点慢,半天没反应,就忍不住又点了一下 —— 结果发了两次请求,搞不好还出现重复登录的 bug。

之前我处理这个问题,除了禁用按钮,还加了个小细节:点了提交后,让焦点留在按钮上。这样用户就算想点别的,也能直观感觉到 “正在处理中,别瞎点了”。

代码大概这样:

<input type="text" placeholder="用户名">
<input type="password" placeholder="密码">
<button id="submitBtn">登录</button>
const submitBtn = document.getElementById('submitBtn');
let isSubmitting = false; // 标记一下:是不是正在提交中

submitBtn.addEventListener('click', async () => {
  if (isSubmitting) return; // 正在提交就别理了,防止点好几次
  
  // 开始提交:按钮禁用,改文字,焦点锁在这里
  isSubmitting = true;
  submitBtn.disabled = true;
  submitBtn.textContent = '登录中...';
  submitBtn.focus(); // 焦点就放这,用户知道“这儿正在干活”
  
  try {
    // 模拟等2秒(比如发请求给后端)
    await new Promise(resolve => setTimeout(resolve, 2000));
    alert('登进去啦!');
  } catch (err) {
    alert('登错了,再试试~');
    // 失败了就恢复按钮,让用户再点
    submitBtn.disabled = false;
    submitBtn.textContent = '重新登录';
  } finally {
    isSubmitting = false;
  }
});

这样用户点了提交后,就算想点别的,焦点也在按钮上,心里有数 “哦,还在处理呢”,就不会瞎点了~

最后唠两句

其实 document.activeElement 这玩意儿,说穿了就是帮你 “搞懂用户现在在干嘛”。它不是什么高大上的功能,但能解决好多 “用户没说但心里吐槽” 的小问题。

比如你写交互时,多想想:用户现在的焦点在哪儿?会不会因为焦点不对,导致操作没反应?用它多做一步判断,网页体验立马就不一样了。

要是你之前也用过这玩意儿,或者有更骚的用法,评论区甩出来咱一起学!毕竟写代码这事儿,互相抄抄作业才进步快嘛~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值