前言
大家好,我是松柏!
不知道大家平时开发的时候喜不喜欢用快捷键呢?我本人是一个重度快捷键用户,在使用 Google 的时候发现,只能点击而不能通过快捷键选中搜索结果。
比如这里我想看第二个搜索结果,那只能通过点击的方式,于是我就在想能不能通过一个简单的脚本给这些搜索结果绑定上快捷键呢?
效果展示
首先给大家看一下最终的效果:
我这里通过 command + option + 序号就能进入特定的搜索结果,比拿起鼠标去点要快多了。
长期累积下来不知道省了多少时间,这些时间拿来学习(摸鱼)不香吗?
实现流程
选择平台(框架)
因为我平时基本都是用 Chrome 浏览器,所以我首先想到的是写一个 Chrome 浏览器插件来实现。但是稍微了解一下之后发现需要注册开发者账号,而且开发成本有点高,跟我的需求不匹配,所以放弃了这个想法。
然后撇到了浏览器上的油猴插件:
突然就觉得或许基于油猴实现会很不错,因为油猴脚本是用 JavaScript 写的,而且之前或多或少接触过,不像 Chrome 插件开发一样没怎么了解过。
实现思路
首先再明确下需求,就是给搜索结果绑定快捷键。
那么可以这样做:
- 获取搜索结果列表
- 在每个搜索结果前放一个序号
- 通过特定按键+序号触发点击事件,点击对应的搜索结果
编码实现
让我们按照上述实现思路来一步步实现。
1)打开 F12 ,可以发现所有的搜索结果带有特定的 class 属性LC20lb MBeuO DKV0Md
。那我们就可以通过这个属性很轻易的获取到搜索结果。
let className = 'LC20lb MBeuO DKV0Md'
document.getElementsByClassName(className)
但这个时候获取到的并不是数组结构,而是 HTMLCollection
对象(本文不深究这个对象,感兴趣可参考文档了解)。
我们可以通过Array.from
将其转为标准的数组对象。
还有一个问题,就是我们其实没有必要获取所有的搜索结果,比如我往下滑了几屏的高度,其实只需要获取到在当前屏幕内的就可以了。
所以我们完善一下这段代码:
// 类名
let className = 'LC20lb MBeuO DKV0Md';
const result = Array.from(document.getElementsByClassName(className)).filter(node => node.getBoundingClientRect().top > 0);
2)接下来通过操作DOM
节点的方式在每个搜索结果前加上一个序号
for (let i = 0; i < result.length; i++) {
const node = result[i];
let newSpan = node.parentNode.getElementsByClassName("p_no")[0];
if (newSpan) {
newSpan.remove();
}
// 创建一个新的 span 元素
newSpan = document.createElement("span");
newSpan.style = 'font-size: 30px;color: skyblue'
newSpan.className = 'p_no'
newSpan.innerHTML = i + 1;
node.parentNode.insertBefore(newSpan, node);// 设置 span 元素的内容
}
3)然后监听键盘的输入事件,并触发相应的click
事件
//获取被按下的键值
let keyNum = window.event ? e.keyCode : e.which;
// 打开页面
if (e.metaKey && e.altKey) {
if (keyNum >= one && keyNum <= nine) {
// 类名
let className = 'LC20lb MBeuO DKV0Md';
const result = Array.from(document.getElementsByClassName(className)).filter(node => node.getBoundingClientRect().top > 0);
result[keyNum - 49].click()
}
}
扩展
我最初的想法是写到这里就可以了,但是发现一个很尴尬的点:如果我可以通过快捷键选择搜索内容,但还是需要鼠标来往下滑动网页,也太抽象了吧!
于是我又想补充一下通过快捷键使网页往下滑动的功能,实践之后发现window.scrollBy
的下滑是跳跃式的,就是直接往下挪了一段距离,没有鼠标往下滑的顺滑感。更尴尬的是我不知道怎么描述我的问题,没法百度。这时候就轮到 AI 出场了,于是就有了下面这段代码:
// 实现滚动动画
function scrollWithAnimation(targetPosition) {
const startPosition = getScrollPosition();
// const distance = targetPosition - startPosition;
const duration = 1500; // 动画持续时间,单位毫秒
let startTime;
function step(timestamp) {
// startTime 开始时间
// timestamp 当前时间
if (!startTime) startTime = timestamp;
// 已执行时间
const progress = timestamp - startTime;
// 当前进度, 0 - 1 之间
const percentage = Math.min(progress / duration, 1);
const easing = easeOutQuad(percentage);
window.scrollBy(0, targetPosition * easing);
if (progress < duration) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
}
// 线性插值函数
function easeOutQuad(t) {
return -1 * t * t + 1;
}
其中值得一提的是,AI 给的代码问题很多(特别是线性插值函数
,测试了半天才搞懂这个函数和滚动动画的关系),不能直接用。但其实已经给我提供了实现方案和思路,这也就够了,稍微改一下就能用了。
完整代码
Github:https://github.com/co-pine/google-search-helper
直接把index.js
的代码复制下来放到油猴中就能直接用啦!
欢迎关注公众号co松柏
交流!