从零写一个基于油猴脚本的 Google 辅助插件(文末附完整代码)

前言

大家好,我是松柏!

不知道大家平时开发的时候喜不喜欢用快捷键呢?我本人是一个重度快捷键用户,在使用 Google 的时候发现,只能点击而不能通过快捷键选中搜索结果。

比如这里我想看第二个搜索结果,那只能通过点击的方式,于是我就在想能不能通过一个简单的脚本给这些搜索结果绑定上快捷键呢?

效果展示

首先给大家看一下最后终的效果:

我这里通过 command + option + 序号就能进入特定的搜索结果,比拿起鼠标去点要快多了。 长期累积下来不知道省了多少时间,这些时间拿来学习(摸鱼)不香吗?

实现流程

选择平台(框架)

因为我平时基本都是用 Chrome 浏览器,所以我首先想到的是写一个 Chrome 浏览器插件来实现。但是稍微了解一下之后发现需要注册开发者账号,而且开发成本有点高,跟我的需求不匹配,所以放弃了这个想法。 然后撇到了浏览器上的油猴插件:

突然就觉得或许基于油猴实现会很不错,因为油猴脚本是用 JavaScript 写的,而且之前或多或少接触过,不像 Chrome 插件开发一样没怎么了解过。

实现思路

首选再明确下需求,就是给搜索结果绑定快捷键。 那么可以这样做:

  1. 获取搜索结果列表
  2. 在每个搜索结果前放一个序号
  3. 通过特定按键+序号触发点击事件,点击对应的搜索结果

编码实现

让我们按照上述实现思路来一步步实现。

1)打开 F12 ,可以发现所有的搜多结果带有特定的 class 属性LC20lb MBeuO DKV0Md。那我们就可以通过这个属性很轻易的获取到搜索结果。

javascript 复制代码
let className = 'LC20lb MBeuO DKV0Md'
document.getElementsByClassName(className)

但这个时候获取到的并不是数组结构,而是 HTMLCollection对象(本文不深究这个对象,感兴趣可参考文档了解)。

我们可以通过Array.from将其转为标准的数组对象。

还有一个问题,就是我们其实没有必要获取所有的搜索结果,比如我往下滑了几屏的高度,其实只需要获取到在当前屏幕内的就可以了。

所以我们完善一下这段代码:

javascript 复制代码
// 类名
let className = 'LC20lb MBeuO DKV0Md';
const result = Array.from(document.getElementsByClassName(className)).filter(node => node.getBoundingClientRect().top > 0);

2)接下来通过操作DOM节点的方式在每个搜索结果前加上一个序号

javascript 复制代码
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事件

javascript 复制代码
//获取被按下的键值
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 出场了,于是就有了下面这段代码:

javascript 复制代码
// 实现滚动动画
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:github.com/co-pine/goo...

直接把index.js的代码复制下来放到油猴中就能直接用啦!有用的话希望点个 star !

欢迎关注同名公众号交流!

相关推荐
Martin -Tang2 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄5 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
喝旺仔la7 小时前
vue的样式知识点
前端·javascript·vue.js
别忘了微笑_cuicui7 小时前
elementUI中2个日期组件实现开始时间、结束时间(禁用日期面板、控制开始时间不能超过结束时间的时分秒)实现方案
前端·javascript·elementui
尝尝你的优乐美7 小时前
vue3.0中h函数的简单使用
前端·javascript·vue.js
windy1a7 小时前
【C语言】js写一个冒泡顺序
javascript
会发光的猪。7 小时前
如何使用脚手架创建一个若依框架vue3+setup+js+vite的项目详细教程
前端·javascript·vue.js·前端框架