浏览器亮度调节
支持调整浏览器中某个页面的亮度;而不需要调整整块屏幕的亮度。
gif图中的是自己开发的 塔防小游戏 感兴趣可以玩玩,要是喜欢可以给个star Github
前言
作为一名小前端,想着浏览器插件技术要求也只需:html,css,js,就萌生了开发一个简单插件试试水的想法,权当丰富技能了。这是第一次尝试开发的浏览器插件比较简陋,轻喷。
使用场景
-
当你觉得某个页面太亮的时候,有些时候的页面是一片白色等浅色背景的,会让你觉得很刺眼,如果使用暗色主题的插件,又会影响到页面其他地方的样式。
-
当你的页面在做正经工作(摸鱼)时,你可以把这个标签页提出来,开启该插件,把亮度调低,这样就能让别人从其他角度难以看到你该页面中的内容。(屏幕其他地方还是亮的,一般人的眼睛都会被亮的地方所吸引)
插件使用方法
下载该文件的压缩包,地址点这里
然后打开 管理扩展插件
,或者在浏览器地址中直接输入: 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)
});
})
首先是修改当前 popup
中 dom
的进度条和进度条的值,然后新的设置 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的知识了,只需要加些拖动等的事件监听就好了,跟浏览器插件知识关系不大,这里就不一一叙述了,想知道的话可以看源码。
至此这个简陋的插件,大体内容就这些了。
待解决的问题
-
当打开遮罩后,刷新页面不会重新打开遮罩,需要点击关闭再重新打开,(记录每个页面对应遮罩是否打开)。
-
移动遮罩层时需要完善宽高问题(目前采用100vmax(浏览器可见区域宽高的最大值))。
-
遮罩层需要支持缩放,可控制来遮罩页面固定区域。
因为本人刚接触,不太熟悉浏览器插件的技术,第1点实现起来有点困难;
对于2,3点,由于是采用 box-shadow
来遮罩页面的,宽高的不同调整 box-shadow
暂时没什么思路。