【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除
背景
上篇 blog
【Ubuntu】【Hugo】搭建私人博客:搜索功能(七)
分析了 onkeydown 的整体目标,以及有时 document.activeElement 可能不可靠的原因,下面继续
搭建私人博客
OK,总之 ae 获得了当前的焦点项,下面继续看不同 key 键的处理

首先,当 key 键为 Escape 时,重置搜索内容,清空输入框,清空结果,光标回到输入框

OK,接下来如果没有搜索结果,或者焦点不在搜索区域,就直接退出,防止在无关区域按方向键还能触发搜索导航

OK,接着是检测到 ↓ 键

- 首先是
e.preventDefault,表示阻止默认滚动行为,因为↓本身有滑动向下的功能,如果不组织默认行为,在键盘导航时,页面也滑动向下的话,体验就不好 - 接着如果当前的焦点是在搜索框的话(
ae == sInput),焦点就从输入框跳到第一个搜索结果(通过activeToggle实现焦点转移)
这里额外说下 resList.firstChild.lastChild,之前在 search.html 模板介绍过这个 HTML 结构如下,resList 是 <ul> 搜索结果集合,firstChild 是 <ul> 搜索结果中的第一个 <li> 列表项,而 lastChild 是 <li> 列表项里最后一个元素 <a href ...>,也就是搜索结果链接

- 最后如果当前的焦点不是搜索框,而是搜索结果中的某一项(但不是最后一项,
ae.parentElement != last),此时就通过activeToggle将焦点向下移动到下一个列表项<li>中的<a href>搜索结果链接
同样这里的 ae.parentElement.nextSibling.last 也展示了焦点的转移过程:当前 <a href> -> 父元素 <li> -> 下一个 <li> -> 它的 <a href>
OK,接下来是检测到 ↑ 键

和前面的 ↓ 键有点类似,逻辑对称,首先 e.preventDefault 同样表示阻止默认滚动行为,然后如果已经在第一项的话,就回到搜索输入框,或者向上移动到上一个结果
OK,下面看最后一个 → 键

这里的 ae.click 表示触发点击事件,跳转页面,用来模拟鼠标点击当前高亮的链接,此时用户按下 → 键,就像点击了一下,非常直观,当然,这里除了 → 键,直接按 Enter 键也是可以跳转的,没问题
OK,下面再回过头看下 activeToggle 的功能

其核心目的是高亮(视觉聚焦)某一个搜索结果项,并清除其他项的高亮状态,用于上面介绍的键盘导航(比如按 ↑ 或者 ↓ 键来选中下一项)
首先是
javascript
document.querySelectorAll('.focus').forEach(function (element) {
element.classList.remove("focus")
});
这里会找到页面上所有带 class="focus" 的元素(一般是 <li> 列表项),然后把它们的 focus 类全部移除,清除所有已有的高亮状态,确保同一时间只有一个结果被高亮,比如

OK,接下来判断是否传入了要激活的元素 ae
javascript
if (ae) {
ae.focus()
document.activeElement = current_elem = ae;
ae.parentElement.classList.add("focus")
}
ae.focus会让这个元素(这里是<a href ...>可跳转链接)获得键盘焦点,然后用户按下 Enter 或者→键就能触发跳转
另外,这里有点小问题,document.activeElement 是只读属性,不应该被赋值

所以这里的实际效果是把 ae 赋值给全局变量 current_elem(供后续导航使用),用于记录当前选中项,但 document.activeElement = ae 完全无效,会被浏览器忽略
ae.parentElement.classList.add("focus"):这里给<a href ...>的父元素,也就是<li>列表项加上 focus 类,会触发 CSS 高亮效果,比如边框,缩放等特殊效果
OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【Ubuntu】【Hugo】搭建私人博客:搜索样式(一)