前端仔尝试开发的浏览器插件(页面亮度调节)

浏览器亮度调节

支持调整浏览器中某个页面的亮度;而不需要调整整块屏幕的亮度。

gif图中的是自己开发的 塔防小游戏 感兴趣可以玩玩,要是喜欢可以给个star Github

前言

作为一名小前端,想着浏览器插件技术要求也只需:html,css,js,就萌生了开发一个简单插件试试水的想法,权当丰富技能了。这是第一次尝试开发的浏览器插件比较简陋,轻喷。

使用场景

  1. 当你觉得某个页面太亮的时候,有些时候的页面是一片白色等浅色背景的,会让你觉得很刺眼,如果使用暗色主题的插件,又会影响到页面其他地方的样式。

  2. 当你的页面在做正经工作(摸鱼)时,你可以把这个标签页提出来,开启该插件,把亮度调低,这样就能让别人从其他角度难以看到你该页面中的内容。(屏幕其他地方还是亮的,一般人的眼睛都会被亮的地方所吸引)

插件使用方法

下载该文件的压缩包,地址点这里

然后打开 管理扩展插件,或者在浏览器地址中直接输入: chrome://extensions/

选择解压后的压缩包的文件夹就可以直接使用了。

插件开发流程

思路

在浏览器页面中设置 fixed 定位一个盒子上去,使用 boxShadow 作为遮罩层,调节 rgab(0,0,0,opacity) 中的透明度作为调节亮度。

结构

写一个插件结构其实很简单(没接触前我还以为会很麻烦),要是没什么特别需求,其实只需要一个 js 文件和一个 manifest.json 的配置文件就可以了。

配置 json

创建 manifest.json 文件

json 复制代码
{
  "name": "browser-mask",
  "description": "Provide a mask layer for the browser.",
  "version": "1.0.1",
  "manifest_version": 3,
  "action": {
    "default_title": "浏览器遮罩层",
    "default_popup": "src/popup.html",
    "default_icon": "images/icon.png"
  },
  "icons": {
    "16": "images/icon.png"
  },
  "permissions": ["storage", "scripting", "activeTab"]
}

最上面三个属性跟 package.json 一样没什么好说的。

  • manifest_version: 这个是 manifest 的版本,2版本的不支持上架了Chrome了。

  • action.default_title: 配置右上角图标标题(鼠标hover就能看到)。

  • action.default_popup: 点击右上角图标打开的那个弹出层页面。

  • action.default_icon: 右上角图标。

  • icons: 这个是管理扩展插件页面中的图标。浏览器地址输入: chrome://extensions/ 直接进入

  • permissions: 开启一些 api 的权限。分别是:storage 开启缓存api;scripting 是开启往页面注入 script 代码的api;activeTab 用于开启标签页api。

popup.js (主要代码)

这是该插件的主要样式了。

html css 没什么好说的,跟正常写一个网页那样。

js 也和写原生大体相同,只是需要注意一些 api 的使用,以及注意变量的作用域等。

插件开始执行

首先检查内存中是否有 opacity 字段,没有就赋值,有的话就给进度条和进度文本赋值。至于这里为什么要用 storage 除了需要缓存之前的值外,还有其他原因,openMask 中会介绍到。

js 复制代码
/** 初始的透明度 */
const INIT_OPACITY = 40;

const progress = document.querySelector('#progress')
const progressValue = document.querySelector('#progressValue')

// ... 其他的一些缓存值,不多叙述了
chrome.storage.sync.get('opacity', ({ opacity: opa }) => {
  if(!opa) {
    chrome.storage.sync.set({ opacity: INIT_OPACITY })
  } else {
    progress.value = opa
    progressValue.textContent = opa
  }
});

打开遮罩层

点击打开按钮,获取到的 tab 就是当前浏览器激活选中的标签页面,然后给这个标签页执行 executeOpenMask 注入执行函数 。

js 复制代码
// #open 是打开按钮的 id 
const openBtn = document.querySelector('#openBtn')
openBtn.addEventListener('click', async () => {
  const tabId = await getTabId();
  const isOpen = await getStorageSync('isOpen')
  if(!isOpen) { // 打开mask
    executeOpenMask(tabId)
  } else { // 关闭mask
    chrome.scripting.executeScript({
      target: { tabId },
      func: closeMask,
    });
  }
  openBtn.textContent = isOpen ? '打开' : '关闭'
  chrome.storage.sync.set({isOpen: !isOpen})
})

/** 获取当前点击的tabId */
async function getTabId() {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  return tab.id
}

/** 获取storage */
function getStorageSync(key) {
  return new Promise((resolve) => {
    chrome.storage.sync.get(key, (item) => {
      resolve(item[key])
    })
  })
}

executeOpenMask

获取 maskInfo(用于存放一些遮罩层的信息,用于缓存而已),往当前标签页中注入 openMask 执行函数,已经传递 maskInfo 参数;再注入 mask.css 的css代码,感兴趣可以直接看源码,就不占文章篇幅了。

js 复制代码
/** 注入打开 mask 的代码 */
async function executeOpenMask(tabId) {
  const maskInfo = await getStorageSync('maskInfo')
  // 获取当前激活的tab的id,注入执行 func
  chrome.scripting.executeScript({
    target: { tabId }, 
    // 这里是传递给 func 的参数
    args: [maskInfo], 
    func: openMask
  });
  chrome.scripting.insertCSS({
    target: { tabId },
    // 这里的路径要按项目根目录开始
    files: ['src/mask.css'] 
  });
  if(maskInfo.isMove) {
    setTimeout(() => {
      chrome.scripting.executeScript({
        target: { tabId },
        args: [maskInfo],
        func: openMaskMove,
      });
    }, 10);
  }
}

openMask

打开遮罩层,这里需要从 storage 中读取 opacity;css 中通过 var(--opacity) 就可获取到值。

css 复制代码
/* mask.css */
#maskWrap {
  box-shadow: 50vmax 50vmax 0 50vmax rgba(0, 0, 0, var(--opacity, 0.4));
}
js 复制代码
function openMask(maskInfo) {
  chrome.storage.sync.get('opacity', ({ opacity }) => {
    const maskWrap = document.createElement('div')
    maskWrap.setAttribute('id', 'maskWrap')
    maskWrap.style.transform = `translate(${maskInfo.x}px, ${maskInfo.y}px)`
    // 给 maskWrap 添加变量
    maskWrap.style.setProperty('--size', 22)
    maskWrap.style.setProperty('--opacity', opacity / 100)
    document.body.appendChild(maskWrap)
  });
}

因为 openMask 是注入的一个函数,存在作用域的问题,是无法读取到外部定义的 opacity。不要问我怎么知道的,因为我刚开始就是这样写的...

js 复制代码
// 这种方式是不正确的,无法使用
let opacity = 40;
function openMask() {
  const maskWrap = document.createElement('div')
  maskWrap.style.setProperty('--opacity', opacity / 100)
  // ....
}

增(减)亮度

增加亮度就是监听增加按钮的点击事件,点击时获取 storage,然后调用 changeOpacity 函数(用来设值和改变界面ui的)即可。

js 复制代码
document.querySelector('.add').addEventListener('click', () => {
  chrome.storage.sync.get('opacity', ({ opacity }) => {
    changeOpacity(opacity + 10)
  });
})

首先是修改当前 popupdom 的进度条和进度条的值,然后新的设置 storage

接着就是修改标签页中的亮度(遮罩层透明度),注入一个触发的函数。

js 复制代码
function changeOpacity(newOpacity) {
  let opacity = Math.min(Math.max(Math.round(newOpacity), 0), 100);
  progress.value = opacity
  progressValue.textContent = opacity
  chrome.storage.sync.set({ opacity })
  chrome.tabs.query({ active: true, currentWindow: true }).then(([tab]) => {
    chrome.scripting.executeScript({
      target: { tabId: tab.id },
      args: [opacity],
      func: injectChangeOpacity,
    });
  })
}
function injectChangeOpacity(opacity) {
  const maskDiv = document.querySelector('#mask')
  if(maskDiv) {
    maskDiv.style.boxShadow = `0 0 0 100vmax rgba(0, 0, 0, ${opacity / 100})`
  }
}

拖动进度条,遮罩层移动等操作就基本只是js的知识了,只需要加些拖动等的事件监听就好了,跟浏览器插件知识关系不大,这里就不一一叙述了,想知道的话可以看源码

至此这个简陋的插件,大体内容就这些了。

待解决的问题

  1. 当打开遮罩后,刷新页面不会重新打开遮罩,需要点击关闭再重新打开,(记录每个页面对应遮罩是否打开)。

  2. 移动遮罩层时需要完善宽高问题(目前采用100vmax(浏览器可见区域宽高的最大值))。

  3. 遮罩层需要支持缩放,可控制来遮罩页面固定区域。

因为本人刚接触,不太熟悉浏览器插件的技术,第1点实现起来有点困难;

对于2,3点,由于是采用 box-shadow 来遮罩页面的,宽高的不同调整 box-shadow 暂时没什么思路。

相关推荐
庸俗今天不摸鱼31 分钟前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX1873032 分钟前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下38 分钟前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox1 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞1 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行1 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758101 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox
掘金一周1 小时前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端
三翼鸟数字化技术团队1 小时前
Vue自定义指令最佳实践教程
前端·vue.js
Jasmin Tin Wei2 小时前
蓝桥杯 web 学海无涯(axios、ecahrts)版本二
前端·蓝桥杯