浏览器插件FeHelper学习:页面取色器

前言

对于大部分前端开发者来说,FeHelper插件应该很多人都用过。我最常用的就是页面取色工具,但是有个小小的不足,获取到的颜色是16进制的,当需要rgb格式时还需要借助FeHelper提供的颜色转换工具进行转换。
本文将学习FeHelper的页面取色功能和颜色转换功能,·并基于这两种开发一个自己的取色工具。

这里要感谢FeHelper作者阿烈叔的开源,可以供大家学习。

参考:https://github.com/zxlie/FeHelper

技术选项

还是使用上一篇文章:快速查找swagger接口的插件 中使用到的jqueryuikit ,感觉这两个拿来写插件是挺不错的。

其他

因为刚开始学习,有些地方不太明白,这次借着学习FeHlper来修改一些东西

  • 依赖注入的匹配
"content_scripts": [
     {
         "matches": [
             "http://*/*",
             "https://*/*",
             "file://*/*"
         ],
         "css": [
             "./uilit/uikit.min.css"
         ],
         "js": [
             "./uilit/uikit.min.js",
             "./uilit/uikit-icons.min.js",
             "./js/jquery.js"
         ]
     }
 ]
  • 判断当前页面是否可以进行依赖注入,原来对于非http(https)的网页会进行报错
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
     let tab = tabs.length ? tabs[0] : null;
     if (tab) {
         if (/^(http(s)?|file):\/\//.test(tabs[0].url)) {
             //依赖注入
         } else {
            sendMessage('抱歉此工具无法在当前页面使用')
         }
     } else {
         sendMessage('请在标签页内使用')
     }
 });

function sendMessage(message) {
    chrome.notifications.create('color-picker-id',
        {
            type: 'basic',
            iconUrl: chrome.runtime.getURL('../img/picker-128.png'),
            title: '温馨提示',
            message: message,
            eventTime: Date.now() + 2000
        }
    )

    setTimeout(() => {
        chrome.notifications.clear('color-picker-id')
    }, 5000)
}

取色器学习

看了一下源代码,没有注释真的是难受。

鼠标移入事件

之前一直想不明白一个问题,那就是如何获取到鼠标移入到的元素。今天打印了一下鼠标对象,发现已经为我们提供了

const abc = document.querySelector('#container');
abc?.addEventListener('mousemove', e => {
    console.log(e.target);
});

浏览器插件FeHelper学习:页面取色器_第1张图片

我们可以直接拿到鼠标移入的dom元素。但这是最基本的东西,如果当某一个元素设置定位属性后,那么你是拿不到你想要的那个元素。
比如当鼠标移入到红色小方块上时,你只能得到这个定位元素。因为这个定位元素更大,如果直接将这个元素的背景色设为黑色,你是看不到的。
浏览器插件FeHelper学习:页面取色器_第2张图片
但是我们的fehelper是可以获取到红色方框的颜色。当然因为有透明的的影响,红色小方块的颜色也不是红色。

canvas

这是另外一个核心。虽然我们没法拿到红色方块,但是我们可以拿到定位元素的父级。然后通过html2canvas把dom转成canvas,通过canvas来获取颜色值。

下载地址:http://html2canvas.hertzen.com/dist/html2canvas.min.js

html2canvas(document.body).then(function(canvas) {
    document.body.appendChild(canvas);
});

当然这里可以优化下,拿到元素后先判断该元素有没有定位属性。如果没有那就是我们要找的元素,直接将这个元素转成canvas,这样可以优化性能(不能直接获取元素的背景色,因为有可能你要获取的是文字的颜色)。

如果是定位元素的话,就找到其父级,将其父级变成canvas(一般情况下,定位元素不多;就算有定位元素,应该也是直接父级;如果最后父级是body,并且有很多子元素,那就自认倒霉,不过检验还是判断一下,如果父级元素是body,并且子元素特别多的话,直接提示获取不到颜色好了)

实现

这里最好先看一下我的这篇文章:通过canvas获取图片的颜色值

  • 当点击按钮后,向页面里注入脚本,通过该脚本实现获取颜色的功能。
//popup.js 依赖注入
chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ["js/handle.js"]
});

这里有个注意点,我想在handle.js里使用jQuery,但是控制台提示找不到。查到的原因是:

popup.js文件和handle.js文件运行在不同的沙箱里,所以不能共享jquery4。您可以尝试使用chrome.runtime.sendMessage和chrome.runtime.onMessage来在不同的脚本之间通信。

这里我们使用原生js来写,写页面通信比较复杂

  • 给body标签上绑定一个鼠标移入事件,用来获取鼠标位置所在的dom元素
body.addEventListener('mouseover', e => {
    console.log("元素是:", e.target)
    target = e.target
})

---------------------------------------------------------------------------分界线-------------------------------------------------------------------------------------

按照上面的思路做完后,我发现是错误的。一开始想的是将尽可能少的dom转成canvas,但是每次都重写创建canvas对象是非常耗时间的。正确的思路是一开始就将body元素转成canvas对象,这样只需要创建一次,后续的操作只是操作这个canvas

第一次尝试后的效果
浏览器插件FeHelper学习:页面取色器_第3张图片
浏览器插件FeHelper学习:页面取色器_第4张图片
第一张图是我自己的demo,第二张图是FeHelper的。可以明显看出存在以下问题:

  • 卡顿,创建的div不能实时跟着鼠标
  • 并且获取到的颜色不是那么准确

优化:

  • 将top、left的改变用平移代替
  • mousemove代替 mouseover,这个才是导致不流畅的根本原因。查了以下两种的区别是:
  • mousemove 是当鼠标在指定的元素内移动时触发的事件,每移动一个像素点就会触发一次。
  • mouseover 是当鼠标从外部进入指定的元素或其子元素时触发的事件,该事件会冒泡。
  • mouseover 和 mouseout 是一对事件,指鼠标移入和移出元素,而 mouseenter 和 mouseleave 是另一对事件,指鼠标移入和移出当前元素,不包括子元素,且不冒泡。

浏览器插件FeHelper学习:页面取色器_第5张图片
从上图可以看到现在已经非常的流畅了,接下来就是细节方面的优化:

  • 修改鼠标的样式
  • 在div中间显示当前的颜色值,在右上角加一个叉号

修改鼠标样式

  • 配置插件可访问的资源
    manifest.json里配置插件可以访问的资源
"web_accessible_resources": [
    {
        "resources": [
            "img/*"
        ],
        "matches": [
            ""
        ]
    }
],

以上代码标识。插件可以在任何url的网页下访问img文件夹下的所有资源。web_accessible_resources是用来设置访问静态资源的,比如图片;而content_scripts 是用来设置可以访问的jscss

//修改鼠标的样式为图片
body.style.cursor = `url(${chrome.runtime.getURL('img/picker-16.png')}),auto`

必须要通过chrome.runtime.getURL才能获取到最终的位置

效果:
浏览器插件FeHelper学习:页面取色器_第6张图片

//添加颜色显示区域
  const colorText = document.createElement('div')
  colorText.id = "color-text"
  colorText.style.cssText = `
                              width:50px;
                              height:20px;
                              position:absolute;
                              bottom:10px;
                              left:45px;
                              border:1px solid #000;
                              text-align:center;
                              line-height:20px;
                              border-radius: 3px;
                              background-color:#fff;
                          `
  divTemplate.appendChild(colorText)

浏览器插件FeHelper学习:页面取色器_第7张图片

问题
发现鼠标放在超链接上,鼠标样式会改变;但是fehelper的不会改变。
解决:修改生成的body的canvas,让他的层级在上面,这样就不会触发到超链接。

// 获取body对应的canvas
 const canvas = await getCanvas()
 //修改canvas的层级
 canvas.style.zIndex = '999'
 canvas.style.position = 'absolute'
 canvas.style.top = "0px"
 canvas.style.left = "0px"
 //将canvas添加到body中
 body.appendChild(canvas)

实现颜色复制

这里就不放关闭图标了,打算通过鼠标左键来复制颜色并关闭插件。关于如何复制之前在

// 这里canvas在最上层,给canvas绑定双击事件
canvas.addEventListener('click', () => {
    //获取剪切板
    const clipboardObj = navigator.clipboard;
    //将颜色写入剪切板
    clipboardObj.writeText(colorText.innerText)

    //注销事件,这里直接将元素移出,更加方便
    body.removeChild(divTemplate)
    body.removeChild(canvas)
})

问题
当第一次使用时可以正常使用,这时已经将脚本注入到了网页。当下一次再点击时,再控制台会报错某个变量已经定义了,导致差距无法正常工作。暂时想到的方法时匿名函数

(()=>{
    // 业务逻辑
})()

最终效果图
可能还存在一些问题,但是这个demo的基本功能已经实现了
浏览器插件FeHelper学习:页面取色器_第8张图片

demo获取

关注我的公众号,回复关键字 取色器 进行demo获取

你可能感兴趣的:(浏览器扩展,学习,javascript,前端)