您2019猪事顺利,心想事成。
Tab 切换是种很常见的网页呈现形式,不管是PC或者H5都会经常看到,今天就为小伙伴们提供多种纯CSS Tab 切换的实现方式,同时对比一下那种代码更方便,更通俗易懂。
3种纯CSS方式实现Tab 切换
纯CSS实现都面临2个问题:
1、 如何接收点击事件?
2、 如何操作相关DOM?
拥有 checked 属性的表单元素, <input type="radio"> 或者 <input type="checkbox"> 能够接收到点击事件。
知识点:
1、 使用 radio 标签的 :checked 伪类,加上 <label for> 实现纯 CSS 捕获点击事情
2、 使用了 ~ 选择符对样式进行控制
<div class="container"> <input class="nav1" id="li1" type="radio" name="nav"> <input class="nav2" id="li2" type="radio" name="nav"> <ul class='nav'> <li class='active'><label for="li1">tab1</label></li> <li><label for="li2">tab2</label></li> </ul> <div class="content"> <div class="content1 default">tab1 内容:123456</div> <div class="content2">tab2 内容:abcdefgkijkl</div> </div> </div>
添加样式
.container *{ padding: 0; margin: 0; } .container { position: relative; width: 400px; margin: 50px auto; } .container input { display: none; } .nav { position: relative; overflow: hidden; } .nav li { width: 200px; float: left; text-align: center; background: #ddd; list-style: none; } .nav li label { display: block; width: 200px; line-height: 36px; font-size: 18px; cursor: pointer; } .content { position: relative; overflow: hidden; width: 400px; height: 100px; border: 1px solid #999; box-sizing: border-box; padding: 10px; } .content1, .content2 { display: none; width: 100%; height: 100%; } .nav1:checked ~ .nav li { background: #ddd; color: #000; } .nav1:checked ~ .nav li:first-child { background: #ff7300; color: #fff; } .nav2:checked ~ .nav li { background: #ddd; color: #000; } .nav2:checked ~ .nav li:last-child { background: #ff7300; color: #fff; } .nav1:checked ~ .content > div { display: none; } .nav1:checked ~ .content > div:first-child { display: block; } .nav2:checked ~ .content > div { display: none; } .nav2:checked ~ .content > div:last-child { display: block; } .nav li.active { background: #ff7300; color: #fff; } .content .default { display: block; }
知识点:
1、 要使用 :target 伪元素,需要 HTML 锚点,以及锚点对应的 HTML 片段
2、 核心是使用 :target 伪类接收点击事件
3、 通过兄弟选择符 ~ 控制样式
<div class="container"> <div id="content1" class="active">tab 1内容:123456</div> <div id="content2">tab 2内容:abcdefgkijkl</div> <ul class='nav'> <li class="active"><a href="#content1">tab1</a></li> <li><a href="#content2">tab2</a></li> </ul> <div class="wrap"></div> </div>
添加样式
.container *{ padding: 0; margin: 0; } .container { position: relative; width: 400px; margin: 50px auto; } .nav { position: relative; overflow: hidden; } li { width: 200px; float: left; text-align: center; background: #ddd; list-style: none; } li a { display: block; width: 200px; line-height: 36px; font-size: 18px; cursor: pointer; text-decoration: none; color: #000; } #content1, #content2 { position: absolute; overflow: hidden; top: 36px; width: 400px; height: 100px; border: 1px solid #999; box-sizing: border-box; padding: 10px; } #content1, #content2 { display: none; width: 100%; background: #fff; } #content1:target, #content2:target { display: block; } #content1.active { display: block; } .active ~ .nav li:first-child { background: #ff7300; color: #fff; } #content1:target ~ .nav li { background: #ddd; color: #000; } #content1:target ~ .nav li:first-child { background: #ff7300; color: #fff; } #content2:target ~ .nav li { background: #ddd; color: #000; } #content2:target ~ .nav li:last-child { background: #ff7300; color: #fff; } .wrap { position: absolute; overflow: hidden; top: 36px; width: 400px; height: 100px; border: 1px solid #999; box-sizing: border-box; }
:focus-within 它表示一个元素获得焦点,或该元素的后代元素获得焦点。
重点:它或它的后代获得焦点。
这也就意味着,它或它的后代获得焦点,都可以触发 :focus-within。
知识点
1、 这个属性有点类似 Javascript 的事件冒泡,从可获焦元素开始一直冒泡到根元素 html,都可以接收触发 :focus-within 事件
2、 本例子的思路就是通过获焦态来控制其他选择器,以及最重要的是利用了父级的 :not(:focus-within) 来设置默认样式
<div class="container"> <div class="nav-box"> <button class="nav1">tab1</button> <button class="nav2">tab2</button> <div class="content-box"> <div class="content1"> content-1 </div> <div class="content2"> content-2 </div> </div> </div> </div>
添加样式
.container { width: 300px; margin: 50px auto; padding: 10px; boder: 1px solid #ddd; } .nav-box { font-size: 0; } button { width: 150px; height: 40px; box-sizing: border-box; outline: none; background: #fff; border: 1px solid #ddd; font-size: 18px; cursor: pointer; } button:focus-within { color: #fff; background: #ff7300; } .content-box { font-size: 24px; border: 1px solid #ddd; height: 100px; } .content-box div { display: none; } .nav-box:not(:focus-within) .nav1 { color: #fff; background: #ff7300; } .nav-box:not(:focus-within) .content1 { display: block; } .nav1:focus-within ~ .content-box .content1 { display: block; } .nav2:focus-within ~ .content-box .content2 { display: block; }
3种纯CSS方式实现Tab 切换
这个效果就很差一些,因为,在tab失去焦点时,就会复原,回到tab1上面,并不推荐这种方式来实现。小编推荐第一种:checked实现方式,更容易理解。
喜欢小编的点击关注,了解更多知识!
源码地址和源文件下载请点击下方“了解更多”
者:中国社会科学院世界经济与政治研究所副研究员 彭成义
近日,美国《反海外腐败法》(又译为《反海外贿赂法》)因《美国陷阱》一书而“名声大噪”。这部由法国电力巨头阿尔斯通前高管皮耶鲁齐所著的新书,通过讲述切身经历及详实考证,揭露了美国如何利用其霸权优势及“长臂管辖”手段打击美国企业海外竞争对手的秘密。如今,在中美贸易摩擦的大背景下,美国又对我国电信巨擘华为故伎重演,并要求加拿大将正在温哥华转机的华为首席财务官孟晚舟进行了扣留。这使得国人对于美国《反海外腐败法》及霸凌行径更加关注并引发热议。由此,有必要深入讨论美国《反海外腐败法》及其滥用情况。
美国《反海外腐败法》的出台与演变
美国《反海外腐败法》的出台,有一个重要的背景和政治诱因,即1977年“水门事件”。“水门事件”的发生,使美国高官和大企业主管这些传统上受人尊重的上层阶层的诚信度遭到社会质疑。媒体借机掀起揭开黑幕运动,社会各界开始普遍要求加强对政府官员和大企业行为的监督,官方被迫启动相关调查。随之,美国证券交易委员会一份报告披露,美国有400多家公司在海外存在非法或者问题交易,引发社会震动。这直接导致美国国会当年便以绝对优势通过《反海外腐败法》,旨在打击美国企业在国外贿赂行为,重建公众对于美国商业系统的信心。
《反海外腐败法》早期的实施效果并不理想,因为它客观上削弱了美国公司在海外市场的竞争力,遭到美国企业界一定程度的抵制,尤其是那些原本可以把行贿支出计入商业成本而获得税收优惠的公司,对此更是怨声载道。由此,美国分别于1988、1994、1998年三次对《反海外腐败法》进行修订,以更适应国际市场的现实情况,同时大力推进《反海外腐败法》的国际化。具体而言,修改后的《反海外腐败法》主要有几个变化。
第一,对国际商业中的一些费用,比如用以促进外国政府机构加快履行日常政府活动的小额支出即“润滑费”,进行了合法化处理。
第二,扩大了该法的适用对象,从先前的美国公司和个人,扩展到和美国有一定关系的外国企业、自然人或者母公司等。只要在美国上市、使用美元结算,或者仅仅通过设在美国的服务器(如谷歌邮箱或微软邮箱)收发、存储(甚至只是过境)电子邮件促成腐败行为发生,这些都被视为利用了美国的国际贸易工具而被纳入该法适用范围。
第三,要求美国总统采取行动,促成其他国家出台与《反海外腐败法》类似的法律。同时,在美国霸权的极力推动下,《反海外腐败法》国际化取得了重要进展。加拿大一些国家就出台类似《反海外腐败法》的国内法。经济合作与发展组织(OECD)则也于1997年颁布《国际商业交易活动反对行贿外国公职人员公约》。
腐败是阻碍人类社会发展的一大毒瘤。特别是在当今全球深度一体化的背景下,没有国家能够独善其身,必须团结起来共同致力于反腐。《反海外腐败法》本是美国单方面的国际反腐行动,但鉴于美国在世界体系中的重要地位,其影响逐渐扩大,在一定程度上推动全球反腐实现了从无到有,并逐渐演变成一个全球腐败治理机制。
当然,我们也必须认识到,美国制定该法律并在国际层面积极推广之,并非全然出于反腐倡廉的道德境界,还有为与苏联争霸谋求道德高地的战略考量。换言之,美国“高尚”行为背后也掺杂着与苏联争霸的私心杂念。而这也为苏联解体后,美国滥用《反海外腐败法》为其私利服务留下了伏笔。
美国《反海外腐败法》被霸权滥用
近年来,美国《反海外腐败法》越来越被霸权滥用。首先,虽然民粹主义可以利用反腐旗号上台,却并非真心反腐,反而往往使腐败形势更加恶化。比如,印度的第一个反腐败政党“普通人党”,在2015年新德里的地方选举中异军突起,一举拿下70个立法会议席中的67个。但是好景不长,很快该党就因为内斗、肮脏政治以及机制失调,而导致公众倍感失望。意大利的著名右翼民粹主义政党也因卷入腐败丑闻而遭受沉重打击,导致该党在2017年的中期选举中丢掉主要大城市的执政权。法国最大的民粹主义政党——国民阵线的主席小勒庞,也因让其保镖及助理等非欧洲议会工作人员在欧洲议会领“空饷”,而被法国司法机关立案调查,并有10余名“国民阵线”议员涉入此案。
其次,美国总统特朗普本身已成为廉政高风险的重点监视对象,其反腐举措更多的是一种“美国优先”的手段。作为民粹主义兴起的代表,特朗普虽然藉着反腐的缘由上台,在竞选期间也反复发出要抽干华盛顿腐败沼泽的豪言壮语,但是其许多举措似乎正在开反腐的倒车。而且,特朗普也因其巨大的商业帝国背景和联系,成为廉政高风险的重点监视对象。国外在这方面的讨论很多,甚至有的民间组织还每月发布特朗普腐败风险监督报告,梳理分析所有可能指控特朗普涉嫌腐败的法律条款等。
不少人认为,特朗普总统及其行政当局某些做法不仅不合乎伦理,而且存在违法行为。特朗普就职不久,华盛顿的一家非盈利组织——“责任与伦理公民”,就正式向地方法院提起了针对特朗普的诉讼,控告特朗普违反了美国宪法中规定的“外国收益条款”。2017年6月中旬,华盛顿特区总检察长卡尔·拉辛及马里兰州总检察长布莱恩·弗洛西也对特朗普提起诉讼,指控他存在“史无前例的违宪行为”。该诉讼还宣称,特朗普所继续拥有的一个全球性的商业帝国已使总统“深深的陷入一个由国外及国内政府行动者组成的集团中”,并且破坏了美国的政治体系的廉洁性。
早在2012年,特朗普就公开抨击《反海外腐败法》为“荒谬和糟糕的法律”。不少观察家担心特朗普会削弱《反海外腐败法》。事实上,特朗普和共和党领导的国会已经放弃奥巴马政府在打击石油和天然气行业反贿赂的努力,美国内务部最近也采取行动停止了对《采掘业透明倡议》的执行。美国退出TPP也被不少人认为是美国反腐的倒退和损失,因为其中有专门的透明与反腐条款将反腐与贸易联系起来,而这耗掉了不少廉政工作者的努力和心血。而且,更令人担忧的是,特朗普的腐败表象以及抵制防止利益冲突举措的态度极可能为国内的其他腐败官员所效仿。
总之,不管是在美国国内还是国外,美国政府过去几十年苦心经营起来的廉洁领袖形象似乎在特朗普当选后短暂的时间里出现了快速的崩塌。开反腐倒车的特朗普政府,无疑已经使以廉洁模范自居的美国开始成为反腐的笑柄。当然,这对全球反腐事业也构成一定的冲击。
然而,就是这样一位对反腐不屑一顾的总统,却在其任上开始大肆启动对外国企业涉嫌贿赂的处罚,力度之大、金额之高令人讶然。这从下图2016-2018年的黄色部分所代表的对外处罚金额就可见一斑。
图1:美国通过《反海外腐败法》对企业实体的处罚一览(图表引自http://fcpa.stanford.edu/statistics-analytics.html?tab=2,2019年6月9日访问)
启示
第一,我们应该客观看待美国《反海外腐败法》的历史功绩。不容否认,美国制定和推广该法对于形成今天全球腐败治理有着重要的推动作用。打造全球廉洁的从商环境无疑仍然具有感召力,并应成为世界各国共同努力的目标。
第二,对于美国利用其霸权优势及长臂管辖手段打击国外竞争企业应该引起世人的高度重视和清醒认识。事实上,不仅是在利用《反海外腐败法》方面,当前特朗普政府的“美国优先”战略正在将其过去几十年辛辛苦苦营造的秩序和制度所葬送。
第三,中国或可扛起促进全球腐败治理的大旗。一方面注重发挥《反海外腐败法》对于国际治理的积极促进作用,另一方面带动全球坚决抵制其被某些霸权私用滥用。这对于进一步提升我国在全球舞台的形象,提高中国智慧和中国方案的感召力,并维护世界的公平与正义,都有重要的意义。
本文主要的内容是帮助读者朋友梳理chrome插件的tabs能力,如果您是第一次阅读本文,也建议您在阅读完本文后,尝试看看我下面的这些系列文章,它们可以更好的帮您认识和了解chrome插件:
一款浏览器插件具备非常强大的能力,它不仅可以向当前所有的站点里注入脚本,对网站的功能进行扩展。更重要的是它还可以和浏览器的标签系统进行交互,从而创建、修改、管理每一个tab,而这一切都基于插件系统为我们提供的tabs相关的API,chrome不仅提供了我们用于操作和管理tabs的API,而且还提供了和content脚本之间的通信方法。
温馨提示:
Tabs API 只能在background脚本中以及option脚本、popup脚本、由chrome创建的tab中访问到,在content脚本中是无法访使用的。
换句话说,chrome有选择性的给不同的脚本环境注入了不同的chrome对象,导致提供的API具备差异性。
该图是我们在特定环境下可以通过chrome.tabs访问的所有的api,这些就是chrome为我们内置的提供给开发者的能力
在之前的文章中我们提到过,如果要使用某些特别的API,我们需要在插件配置文件manifest.json中配置相应的权限声明,但幸运的是对于tabs相关的部分API不需要在manifest.json中显式的配置“tabs”就可以直接使用。比如说: 创建一个新的tab,重新加载某个tab,或者导航到另外一个URL等等。
但是下面的这些API在使用的时候,则需要加上相关的配置才可以使用,比如说:
chrome.tabs.executeScript() // 注入一段脚本并执行
chrome.tabs.insertCss() // 注入一段css样式
chrome.tabs.removeCss() // 移除一段css样式
{
// manifest.json "host_permissions":[ "<all_urls>" ] // 支持正则匹配正则
}
接下来我们一一通过案例来认识他们,从而感受每一个API的具体行为以及他们的使用条件、注意事项等等。
我们可以通过这个API来创建一个新的tab,这个tab和普通的站点不一样,属于插件所属的页面,因此支持跨域请求、获取更多的chrome提供的方法。
// background.js
chrome.runtime.onInstalled.addListener(({reason})=> {
if (reason==='install') {
chrome.tabs.create({
url: "newtab.html" // 相对于background脚本的路径下需要有一个newtab.html文件
});
}
});
上面的脚本意味着在插件第一次安装完成之后,就会立马创建一个新的标签页,所以如果我们想要在任何时候创建一个新的tab,就可以使用这个API,行业内很多插件的工作台都是创建一个新的tab页进行工作的,比如著名的代理插件SwitchySharp
该api默认支持,不需要额外的manifest配置
我们可能有这样的需要,获取当前浏览器窗口处于激活状态的tab页面,因为对于同一个窗口,有且只有会一个tab是展示在用户面前的,我们把这样的tab称为激活状态,这个时候我们就需要用到下面的api。
async function getCurrentTab() { let queryOptions={ active: true }; let [tab]=await chrome.tabs.query(queryOptions); return tab; }
调用上面的方法,你就可以获得当前窗口激活的那个tab的实例对象了,从这个对象中,你可以获取到对应的tab唯一的id、url、图标等信息。
值得注意的是,如果chrome浏览器打开了多个窗口,就意味着可能每一个窗口都会存在一个激活的tab,因此我们获取的tab就会是多个,这个时候如果只是解构出第一个可能是不够严谨的。
因此我们可以通过添加搜索条件来精确的查找:
async function getCurrentTab() {
let queryOptions={
active: true , currentWindow:true
};
let [tab]=await
chrome.tabs.query(queryOptions);
return tab;
}
通过添加一个参数currentWindow,意味着只搜索脚本运行所在窗口的激活的tab,这个时候肯定只会查找出唯一的一个tab,解构第一个就不会有问题。
搜索条件除了上述之外,还有下面可以选择:
参数 | 类型 | 作用 |
active | boolean | 是否处于激活状态 |
audible | boolean | 是否处于播放音频状态 |
currentWindow | boolean | 是否处于脚本所在窗口内 |
groupId | number | 是否处于某个分组内 |
highlighted | boolean | 是否处于高亮状态 |
index | number | 窗口从左往右第index个tab |
pinned | boolean | 是否处于被固定的状态 |
status | unloaded/loading/complete | 匹配tab的status为该status的tabs |
title | string | 匹配tab的title为该title的tabs |
url | string | 匹配tab的url为该url的tabs |
windowId | number | 特定窗口下的tabs |
windowType | normal/popup/panel/app/devtools | 特定的窗口类型下所在的tabs |
被固定是指那些通过右键点击tab的时候,选择固定在最左侧的标签,并且可以固定多个。
该api默认支持,需要额外的manifest配置,需要显式声明“tabs”的permissions
我们可以很方便的给指定的tab发送消息,一般来说我们可以在content脚本中做消息的监听,接收到消息后使其执行不同的业务逻辑。
chrome.tabs.sendMessage(
tabId: number, // 目标tab的id
message: any, // 发送信息
options?: object, // 其他配置项
callback?: function, // 回调函数 )
上面这个是V3版本的插件使用的,在V2版本中我们使用chrome.tabs.sendRquest()
// 在v3版本中已废弃
chrome.tabs.sendRequest(
tabId: number, // 目标tab的id
request: any, // 发送信息
callback?: function, // 回调函数
)
如果我们希望修改一个tab的一些参数信息,我们可以选择使用下面这个API:
chrome.tabs.update( tabId?: number, updateProperties: object, callback?: function, )
其中updateProperties的值就是上面提到的queryOptions的属性保持一致,例如我们可以动态的更改指定tab的title、url、pinned等状态属性!
当我们按住ctrl的同时再滑动鼠标滚轮的话就可以调整页面的缩放比例,这个可能大家平时都深有体会,但是实际上这个也可以通过插件给我们提供的API来动态的进行调整:
chrome.tabs.setZoom( tabId?: number, zoomFactor: number, // 缩放比例 callback?: function, )
我们介绍的第一个API就展示了如何创建一个新的tab,他会默认创建在最末尾,也就是最右侧,如果这个放置位置我们不满意,我们也可以将其放置在我们想要的位置。
移动
chrome.tabs.move(
tabIds: number | number[],
moveProperties: object,
callback?: function,
)
type moveProperties={ index?:number, // 想要移动至的index索引位置. `-1` 移动至窗口末尾.
windowId?:number // 移动至的窗口id
}
移除
chrome.tabs.remove( tabIds: number | number[], callback?: function, )
刷新
chrome.tabs.reload( tabId?: number, reloadProperties?: object, callback?: function, ) type reloadProperties={ bypassCache?:boolean // 是否绕过本地缓存 默认不绕过,也就是使用本地缓存。 }
我们可以通过插件来控制一个tab的前进后退(如果他们都曾有过跳转的记录)
chrome.tabs.goBack( // 回到最近的一次历史记录 tabId?: number, callback?: function, ) chrome.tabs.goForward( // 去到下一个历史记录,如果有的话 tabId?: number, callback?: function, )
当我们的tab开的特别多的时候,浏览器会有个小优化,对于某些长时间不用的tab,浏览器会清空内存中对其的状态存贮,因此当我们再次将其激活时会重新加载!这个过程插件也提供了API可以帮助我们做到:
chrome.tabs.discard( tabId?: number, callback?: function, ) chrome.tabs.duplicate( // 这个API与discard相反,可以帮助我们复制一个一摸一样的tab标签 tabId: number, callback?: function, )
如果我们希望将某些具备相似特征的网站分成一个组,使其能够在视图上更好的被察觉,那么我们就可以通过插件为我们提供的API来进行实现:
第一步:筛选出希望分到同一组的tabs
const tabs=await chrome.tabs.query({ url: [ "https://developer.chrome.com/*"], });
根据前面的知识,我们很容易就可以知道tabs就是域名为 "developer.chrome.com" 开头的所有站点的tab集合;
第二步:将他们分为一组
const tabIds=tabs.map(({ id })=> id); const group=await chrome.tabs.group({ tabIds });
上图中就可以看到所有符合条件的站点就被分为同一个组了,这个API的使用方式是:
chrome.tabs.group( options: GroupOptions, callback?: function, ) type GroupOptions={ tabIds?:number[], // 希望被分组的tab的id的集合 groupId?:number, // 已有的分组 createProperties?:{ windowId?:number // 希望分组被创建在那个窗口, 默认是脚本所在窗口 } }
额外的话:
如果我们希望在分组上再加上一个样式或者字样作为标记的话,也可以这样做:
// 第一步: 在manifest.json中添加“tabGrpups”的权限 { ... "permissions":[ "tabGroups" ] } //第二步: chrome.tabGroups.update(group, { title: "这是分组1" , color:'red' });
就可以修改这个分组的一些特征,上面是增加了一个标题,效果如下:
以上我们介绍了基本的API,接下来我们通过一些案例来实际感受一下每个API的作用:
准备以下的项目:
manifest.json
{
"name": "tabs demo",
"description": "tabs demo",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "popup.html",
"default_icon":
{
"16": "/images/get_started16.png",
"32": "/images/get_started32.png",
"48": "/images/get_started48.png",
"128": "/images/get_started128.png"
}
},
"content_scripts": [
{
"js": ["content.js"],
"matches": ["<all_urls>"] } ],
"background":
{
"service_worker": "background.js"
},
"icons": {
"16": "/images/get_started16.png",
"32": "/images/get_started32.png",
"48": "/images/get_started48.png",
"128": "/images/get_started128.png"
},
"permissions": ["tabs", "tabGroups"] }
content.js / background.js
// content.js let color=""; console.log("content.js"); chrome.runtime.onMessage.addListener((message, sender, sendResponse)=> { color=document.body.style.color; document.body.style.background=message; sendResponse("changed"); }); // background.js console.log(chrome);
newtab.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>chrome插件</title> </head> <body> <h1>我是一个由chrome插件创建的页面</h1> </body> </html>
popup.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <section> <h1>创建新的页面</h1> <button id="create-tab">创建</button> </section> <section> <h1>查找符合条件的tab</h1> <div> <span>是否激活</span> <span>是</span> <input type="radio" name="isActive" value="1" /> <span>否</span> <input type="radio" name="isActive" value="0" /> </div> <div> <span>是否属于当前窗口:</span> <span>是</span> <input type="radio" name="isCurrentWindow" value="1" /> <span>否</span> <input type="radio" name="isCurrentWindow" value="0" /> </div> <div> <span>url(支持正则):</span> <input type="text" id="url" /> </div> <div> <span>title</span> <input type="text" id="title" /> </div> <div> <span>index</span> <input type="text" id="index" /> </div> <div> <span>是否被固定</span> <span>是</span> <input type="radio" name="pinned" value="1" /> <span>否</span> <input type="radio" name="pinned" value="0" /> </div> <div> <span>status</span> <select name="status" id="status"> <option value="unloaded">unloaded</option> <option value="loading">unloaded</option> <option value="complete">unloaded</option> </select> </div> <button id="query-tab">查找</button> <div> <div>查找结果:</div> <div id="search-result"></div> </div> </section> <section> <h1>发送消息</h1> <input type="color" id="send-value" /> <button id="send-btn">变色吧</button> </section> <section> <h1>删/改/移/丢弃/复制</h1> <div> <input type="text" id="move-index" /> <button id="move">移动当前的tab</button> </div> <div> <button id="remove">移除当前的tab</button> </div> <div> <button id="reload">刷新当前的tab</button> </div> <div> <input type="text" id="discard-value" /> <button id="discard">丢弃</button> </div> <div> <button id="duplicate">复制</button> </div> <div> <input type="text" id="update-value" /> <button id="update">更新</button> </div> </section> <section> <h1>缩放比</h1> <div> <input type="text" id="zoom" /> <button id="zoom-btn">调整</button> </div> </section> <section> <h1>分组</h1> <div> <input type="text" id="group-title" /> <button id="group">使用查询的结果进行分组</button> </div> </section> <section> <h1>导航</h1> <div> <button id="goForward">前进</button> <button id="goBack">前进</button> </div> </section> <script src="./popup.js"></script> </body> </html>
popup.js
document.getElementById("create-tab").addEventListener("click", ()=> { chrome.tabs.create({ url: "newtab.html", // 相对于background脚本的路径下需要有一个newtab.html文件 }); }); let Tabs=[]; const getSelect=(list)=> { const yes=list[0]; const no=list[1]; if (yes.checked) { return yes.defaultValue==="1"; } if (no.checked) { return no.defaultValue==="1"; } return false; }; document.getElementById("query-tab").addEventListener("click", async ()=> { const active=getSelect(document.getElementsByName("isActive")); const currentWindow=getSelect( document.getElementsByName("isCurrentWindow") ); const pinned=getSelect(document.getElementsByName("pinned")); const url=document.getElementById("url").value; const title=document.getElementById("title").value; const index=document.getElementById("index").value; const queryOptions={ active, currentWindow, pinned, }; if (url) { queryOptions.url=url; } if (title) { queryOptions.title=title; } if (index) { queryOptions.index=index - 0; } console.log(queryOptions); const tabs=await chrome.tabs.query(queryOptions); document.getElementById("search-result").innerHTML=JSON.stringify( tabs.map(({ id })=> ({ id })) ); Tabs=tabs; }); document.getElementById("send-btn").addEventListener("click", async ()=> { const color=document.getElementById("send-value").value; const [tab]=await chrome.tabs.query({ active: true, currentWindow: true }); const response=await chrome.tabs.sendMessage(tab.id, color); console.log(color, response); }); const getCurrentTab=async ()=> { const [tab]=await chrome.tabs.query({ active: true, currentWindow: true }); return tab.id; }; document.getElementById("move").addEventListener("click", async ()=> { const index=document.getElementById("move-index").value - 0; const tabIds=await getCurrentTab(); chrome.tabs.move(tabIds, { index }); }); document.getElementById("remove").addEventListener("click", async ()=> { const tabIds=await getCurrentTab(); chrome.tabs.remove(tabIds); }); document.getElementById("reload").addEventListener("click", async ()=> { const tabId=await getCurrentTab(); chrome.tabs.reload(tabId); }); document.getElementById("discard").addEventListener("click", async ()=> { const tabId=document.getElementById("discard-value").value - 0; chrome.tabs.discard(tabId); }); document.getElementById("duplicate").addEventListener("click", async ()=> { const tabId=await getCurrentTab(); chrome.tabs.duplicate(tabId); }); document.getElementById("zoom-btn").addEventListener("click", async ()=> { const tabId=await getCurrentTab(); const zoomFactor=document.getElementById("zoom").value - 0; chrome.tabs.setZoom(tabId, zoomFactor); }); document.getElementById("group").addEventListener("click", async ()=> { const tabIds=Tabs.map(({ id })=> id); const title=document.getElementById("group-title").value; const group=await chrome.tabs.group({ tabIds }); chrome.tabGroups.update(group, { color: "red", title }); }); document.getElementById("goForward").addEventListener("click", async ()=> { const tabId=await getCurrentTab(); chrome.tabs.goForward(tabId); }); document.getElementById("goBack").addEventListener("click", async ()=> { const tabId=await getCurrentTab(); chrome.tabs.goBack(tabId); });
以上的资源我会放到github上,大家可以download下来直接在自己的浏览器上运行,查看效果,也希望有收获后给不吝star哈!。
下面是我本地的测试效果:
创建页面/发送消息
查询
删/改/更新
分组
有了以上的武器,就可以玩转tabs啦!一起开始开发chrome插件吧!
以下是我的其他文章,欢迎阅读
保姆级讲解JS精度丢失问题(图文结合)
shell、bash、zsh、powershell、gitbash、cmd这些到底都是啥?
从0到1开发一个浏览器插件(通俗易懂)
用零碎时间个人建站(200+赞)
另外我有一个自己的网站,欢迎来看看 new-story.cn
创作不易,如果您觉得文章有任何帮助到您的地方,或者触碰到了自己的知识盲区,请帮我点赞收藏一下,或者关注我,我会产出更多高质量文章,最后感谢您的阅读,祝愿大家越来越好。
*请认真填写需求信息,我们会在24小时内与您取得联系。