您2019豬事順利,心想事成。
Tab 切換是種很常見的網(wǎng)頁呈現(xiàn)形式,不管是PC或者H5都會經(jīng)常看到,今天就為小伙伴們提供多種純CSS Tab 切換的實現(xiàn)方式,同時對比一下那種代碼更方便,更通俗易懂。
3種純CSS方式實現(xiàn)Tab 切換
純CSS實現(xiàn)都面臨2個問題:
1、 如何接收點擊事件?
2、 如何操作相關(guān)DOM?
擁有 checked 屬性的表單元素, <input type="radio"> 或者 <input type="checkbox"> 能夠接收到點擊事件。
知識點:
1、 使用 radio 標(biāo)簽的 :checked 偽類,加上 <label for> 實現(xiàn)純 CSS 捕獲點擊事情
2、 使用了 ~ 選擇符對樣式進(jìn)行控制
<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 內(nèi)容:123456</div> <div class="content2">tab2 內(nèi)容: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 錨點,以及錨點對應(yīng)的 HTML 片段
2、 核心是使用 :target 偽類接收點擊事件
3、 通過兄弟選擇符 ~ 控制樣式
<div class="container"> <div id="content1" class="active">tab 1內(nèi)容:123456</div> <div id="content2">tab 2內(nèi)容: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 它表示一個元素獲得焦點,或該元素的后代元素獲得焦點。
重點:它或它的后代獲得焦點。
這也就意味著,它或它的后代獲得焦點,都可以觸發(fā) :focus-within。
知識點
1、 這個屬性有點類似 Javascript 的事件冒泡,從可獲焦元素開始一直冒泡到根元素 html,都可以接收觸發(fā) :focus-within 事件
2、 本例子的思路就是通過獲焦態(tài)來控制其他選擇器,以及最重要的是利用了父級的 :not(:focus-within) 來設(shè)置默認(rèn)樣式
<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方式實現(xiàn)Tab 切換
這個效果就很差一些,因為,在tab失去焦點時,就會復(fù)原,回到tab1上面,并不推薦這種方式來實現(xiàn)。小編推薦第一種:checked實現(xiàn)方式,更容易理解。
喜歡小編的點擊關(guān)注,了解更多知識!
源碼地址和源文件下載請點擊下方“了解更多”
者:中國社會科學(xué)院世界經(jīng)濟(jì)與政治研究所副研究員 彭成義
近日,美國《反海外腐敗法》(又譯為《反海外賄賂法》)因《美國陷阱》一書而“名聲大噪”。這部由法國電力巨頭阿爾斯通前高管皮耶魯齊所著的新書,通過講述切身經(jīng)歷及詳實考證,揭露了美國如何利用其霸權(quán)優(yōu)勢及“長臂管轄”手段打擊美國企業(yè)海外競爭對手的秘密。如今,在中美貿(mào)易摩擦的大背景下,美國又對我國電信巨擘華為故伎重演,并要求加拿大將正在溫哥華轉(zhuǎn)機(jī)的華為首席財務(wù)官孟晚舟進(jìn)行了扣留。這使得國人對于美國《反海外腐敗法》及霸凌行徑更加關(guān)注并引發(fā)熱議。由此,有必要深入討論美國《反海外腐敗法》及其濫用情況。
美國《反海外腐敗法》的出臺與演變
美國《反海外腐敗法》的出臺,有一個重要的背景和政治誘因,即1977年“水門事件”。“水門事件”的發(fā)生,使美國高官和大企業(yè)主管這些傳統(tǒng)上受人尊重的上層階層的誠信度遭到社會質(zhì)疑。媒體借機(jī)掀起揭開黑幕運動,社會各界開始普遍要求加強(qiáng)對政府官員和大企業(yè)行為的監(jiān)督,官方被迫啟動相關(guān)調(diào)查。隨之,美國證券交易委員會一份報告披露,美國有400多家公司在海外存在非法或者問題交易,引發(fā)社會震動。這直接導(dǎo)致美國國會當(dāng)年便以絕對優(yōu)勢通過《反海外腐敗法》,旨在打擊美國企業(yè)在國外賄賂行為,重建公眾對于美國商業(yè)系統(tǒng)的信心。
《反海外腐敗法》早期的實施效果并不理想,因為它客觀上削弱了美國公司在海外市場的競爭力,遭到美國企業(yè)界一定程度的抵制,尤其是那些原本可以把行賄支出計入商業(yè)成本而獲得稅收優(yōu)惠的公司,對此更是怨聲載道。由此,美國分別于1988、1994、1998年三次對《反海外腐敗法》進(jìn)行修訂,以更適應(yīng)國際市場的現(xiàn)實情況,同時大力推進(jìn)《反海外腐敗法》的國際化。具體而言,修改后的《反海外腐敗法》主要有幾個變化。
第一,對國際商業(yè)中的一些費用,比如用以促進(jìn)外國政府機(jī)構(gòu)加快履行日常政府活動的小額支出即“潤滑費”,進(jìn)行了合法化處理。
第二,擴(kuò)大了該法的適用對象,從先前的美國公司和個人,擴(kuò)展到和美國有一定關(guān)系的外國企業(yè)、自然人或者母公司等。只要在美國上市、使用美元結(jié)算,或者僅僅通過設(shè)在美國的服務(wù)器(如谷歌郵箱或微軟郵箱)收發(fā)、存儲(甚至只是過境)電子郵件促成腐敗行為發(fā)生,這些都被視為利用了美國的國際貿(mào)易工具而被納入該法適用范圍。
第三,要求美國總統(tǒng)采取行動,促成其他國家出臺與《反海外腐敗法》類似的法律。同時,在美國霸權(quán)的極力推動下,《反海外腐敗法》國際化取得了重要進(jìn)展。加拿大一些國家就出臺類似《反海外腐敗法》的國內(nèi)法。經(jīng)濟(jì)合作與發(fā)展組織(OECD)則也于1997年頒布《國際商業(yè)交易活動反對行賄外國公職人員公約》。
腐敗是阻礙人類社會發(fā)展的一大毒瘤。特別是在當(dāng)今全球深度一體化的背景下,沒有國家能夠獨善其身,必須團(tuán)結(jié)起來共同致力于反腐。《反海外腐敗法》本是美國單方面的國際反腐行動,但鑒于美國在世界體系中的重要地位,其影響逐漸擴(kuò)大,在一定程度上推動全球反腐實現(xiàn)了從無到有,并逐漸演變成一個全球腐敗治理機(jī)制。
當(dāng)然,我們也必須認(rèn)識到,美國制定該法律并在國際層面積極推廣之,并非全然出于反腐倡廉的道德境界,還有為與蘇聯(lián)爭霸謀求道德高地的戰(zhàn)略考量。換言之,美國“高尚”行為背后也摻雜著與蘇聯(lián)爭霸的私心雜念。而這也為蘇聯(lián)解體后,美國濫用《反海外腐敗法》為其私利服務(wù)留下了伏筆。
美國《反海外腐敗法》被霸權(quán)濫用
近年來,美國《反海外腐敗法》越來越被霸權(quán)濫用。首先,雖然民粹主義可以利用反腐旗號上臺,卻并非真心反腐,反而往往使腐敗形勢更加惡化。比如,印度的第一個反腐敗政黨“普通人黨”,在2015年新德里的地方選舉中異軍突起,一舉拿下70個立法會議席中的67個。但是好景不長,很快該黨就因為內(nèi)斗、骯臟政治以及機(jī)制失調(diào),而導(dǎo)致公眾倍感失望。意大利的著名右翼民粹主義政黨也因卷入腐敗丑聞而遭受沉重打擊,導(dǎo)致該黨在2017年的中期選舉中丟掉主要大城市的執(zhí)政權(quán)。法國最大的民粹主義政黨——國民陣線的主席小勒龐,也因讓其保鏢及助理等非歐洲議會工作人員在歐洲議會領(lǐng)“空餉”,而被法國司法機(jī)關(guān)立案調(diào)查,并有10余名“國民陣線”議員涉入此案。
其次,美國總統(tǒng)特朗普本身已成為廉政高風(fēng)險的重點監(jiān)視對象,其反腐舉措更多的是一種“美國優(yōu)先”的手段。作為民粹主義興起的代表,特朗普雖然藉著反腐的緣由上臺,在競選期間也反復(fù)發(fā)出要抽干華盛頓腐敗沼澤的豪言壯語,但是其許多舉措似乎正在開反腐的倒車。而且,特朗普也因其巨大的商業(yè)帝國背景和聯(lián)系,成為廉政高風(fēng)險的重點監(jiān)視對象。國外在這方面的討論很多,甚至有的民間組織還每月發(fā)布特朗普腐敗風(fēng)險監(jiān)督報告,梳理分析所有可能指控特朗普涉嫌腐敗的法律條款等。
不少人認(rèn)為,特朗普總統(tǒng)及其行政當(dāng)局某些做法不僅不合乎倫理,而且存在違法行為。特朗普就職不久,華盛頓的一家非盈利組織——“責(zé)任與倫理公民”,就正式向地方法院提起了針對特朗普的訴訟,控告特朗普違反了美國憲法中規(guī)定的“外國收益條款”。2017年6月中旬,華盛頓特區(qū)總檢察長卡爾·拉辛及馬里蘭州總檢察長布萊恩·弗洛西也對特朗普提起訴訟,指控他存在“史無前例的違憲行為”。該訴訟還宣稱,特朗普所繼續(xù)擁有的一個全球性的商業(yè)帝國已使總統(tǒng)“深深的陷入一個由國外及國內(nèi)政府行動者組成的集團(tuán)中”,并且破壞了美國的政治體系的廉潔性。
早在2012年,特朗普就公開抨擊《反海外腐敗法》為“荒謬和糟糕的法律”。不少觀察家擔(dān)心特朗普會削弱《反海外腐敗法》。事實上,特朗普和共和黨領(lǐng)導(dǎo)的國會已經(jīng)放棄奧巴馬政府在打擊石油和天然氣行業(yè)反賄賂的努力,美國內(nèi)務(wù)部最近也采取行動停止了對《采掘業(yè)透明倡議》的執(zhí)行。美國退出TPP也被不少人認(rèn)為是美國反腐的倒退和損失,因為其中有專門的透明與反腐條款將反腐與貿(mào)易聯(lián)系起來,而這耗掉了不少廉政工作者的努力和心血。而且,更令人擔(dān)憂的是,特朗普的腐敗表象以及抵制防止利益沖突舉措的態(tài)度極可能為國內(nèi)的其他腐敗官員所效仿。
總之,不管是在美國國內(nèi)還是國外,美國政府過去幾十年苦心經(jīng)營起來的廉潔領(lǐng)袖形象似乎在特朗普當(dāng)選后短暫的時間里出現(xiàn)了快速的崩塌。開反腐倒車的特朗普政府,無疑已經(jīng)使以廉潔模范自居的美國開始成為反腐的笑柄。當(dāng)然,這對全球反腐事業(yè)也構(gòu)成一定的沖擊。
然而,就是這樣一位對反腐不屑一顧的總統(tǒng),卻在其任上開始大肆啟動對外國企業(yè)涉嫌賄賂的處罰,力度之大、金額之高令人訝然。這從下圖2016-2018年的黃色部分所代表的對外處罰金額就可見一斑。
圖1:美國通過《反海外腐敗法》對企業(yè)實體的處罰一覽(圖表引自http://fcpa.stanford.edu/statistics-analytics.html?tab=2,2019年6月9日訪問)
啟示
第一,我們應(yīng)該客觀看待美國《反海外腐敗法》的歷史功績。不容否認(rèn),美國制定和推廣該法對于形成今天全球腐敗治理有著重要的推動作用。打造全球廉潔的從商環(huán)境無疑仍然具有感召力,并應(yīng)成為世界各國共同努力的目標(biāo)。
第二,對于美國利用其霸權(quán)優(yōu)勢及長臂管轄手段打擊國外競爭企業(yè)應(yīng)該引起世人的高度重視和清醒認(rèn)識。事實上,不僅是在利用《反海外腐敗法》方面,當(dāng)前特朗普政府的“美國優(yōu)先”戰(zhàn)略正在將其過去幾十年辛辛苦苦營造的秩序和制度所葬送。
第三,中國或可扛起促進(jìn)全球腐敗治理的大旗。一方面注重發(fā)揮《反海外腐敗法》對于國際治理的積極促進(jìn)作用,另一方面帶動全球堅決抵制其被某些霸權(quán)私用濫用。這對于進(jìn)一步提升我國在全球舞臺的形象,提高中國智慧和中國方案的感召力,并維護(hù)世界的公平與正義,都有重要的意義。
本文主要的內(nèi)容是幫助讀者朋友梳理chrome插件的tabs能力,如果您是第一次閱讀本文,也建議您在閱讀完本文后,嘗試看看我下面的這些系列文章,它們可以更好的幫您認(rèn)識和了解chrome插件:
一款瀏覽器插件具備非常強(qiáng)大的能力,它不僅可以向當(dāng)前所有的站點里注入腳本,對網(wǎng)站的功能進(jìn)行擴(kuò)展。更重要的是它還可以和瀏覽器的標(biāo)簽系統(tǒng)進(jìn)行交互,從而創(chuàng)建、修改、管理每一個tab,而這一切都基于插件系統(tǒng)為我們提供的tabs相關(guān)的API,chrome不僅提供了我們用于操作和管理tabs的API,而且還提供了和content腳本之間的通信方法。
溫馨提示:
Tabs API 只能在background腳本中以及option腳本、popup腳本、由chrome創(chuàng)建的tab中訪問到,在content腳本中是無法訪使用的。
換句話說,chrome有選擇性的給不同的腳本環(huán)境注入了不同的chrome對象,導(dǎo)致提供的API具備差異性。
該圖是我們在特定環(huán)境下可以通過chrome.tabs訪問的所有的api,這些就是chrome為我們內(nèi)置的提供給開發(fā)者的能力
在之前的文章中我們提到過,如果要使用某些特別的API,我們需要在插件配置文件manifest.json中配置相應(yīng)的權(quán)限聲明,但幸運的是對于tabs相關(guān)的部分API不需要在manifest.json中顯式的配置“tabs”就可以直接使用。比如說: 創(chuàng)建一個新的tab,重新加載某個tab,或者導(dǎo)航到另外一個URL等等。
但是下面的這些API在使用的時候,則需要加上相關(guān)的配置才可以使用,比如說:
chrome.tabs.executeScript() // 注入一段腳本并執(zhí)行
chrome.tabs.insertCss() // 注入一段css樣式
chrome.tabs.removeCss() // 移除一段css樣式
{
// manifest.json "host_permissions":[ "<all_urls>" ] // 支持正則匹配正則
}
接下來我們一一通過案例來認(rèn)識他們,從而感受每一個API的具體行為以及他們的使用條件、注意事項等等。
我們可以通過這個API來創(chuàng)建一個新的tab,這個tab和普通的站點不一樣,屬于插件所屬的頁面,因此支持跨域請求、獲取更多的chrome提供的方法。
// background.js
chrome.runtime.onInstalled.addListener(({reason})=> {
if (reason==='install') {
chrome.tabs.create({
url: "newtab.html" // 相對于background腳本的路徑下需要有一個newtab.html文件
});
}
});
上面的腳本意味著在插件第一次安裝完成之后,就會立馬創(chuàng)建一個新的標(biāo)簽頁,所以如果我們想要在任何時候創(chuàng)建一個新的tab,就可以使用這個API,行業(yè)內(nèi)很多插件的工作臺都是創(chuàng)建一個新的tab頁進(jìn)行工作的,比如著名的代理插件SwitchySharp
該api默認(rèn)支持,不需要額外的manifest配置
我們可能有這樣的需要,獲取當(dāng)前瀏覽器窗口處于激活狀態(tài)的tab頁面,因為對于同一個窗口,有且只有會一個tab是展示在用戶面前的,我們把這樣的tab稱為激活狀態(tài),這個時候我們就需要用到下面的api。
async function getCurrentTab() { let queryOptions={ active: true }; let [tab]=await chrome.tabs.query(queryOptions); return tab; }
調(diào)用上面的方法,你就可以獲得當(dāng)前窗口激活的那個tab的實例對象了,從這個對象中,你可以獲取到對應(yīng)的tab唯一的id、url、圖標(biāo)等信息。
值得注意的是,如果chrome瀏覽器打開了多個窗口,就意味著可能每一個窗口都會存在一個激活的tab,因此我們獲取的tab就會是多個,這個時候如果只是解構(gòu)出第一個可能是不夠嚴(yán)謹(jǐn)?shù)摹?/span>
因此我們可以通過添加搜索條件來精確的查找:
async function getCurrentTab() {
let queryOptions={
active: true , currentWindow:true
};
let [tab]=await
chrome.tabs.query(queryOptions);
return tab;
}
通過添加一個參數(shù)currentWindow,意味著只搜索腳本運行所在窗口的激活的tab,這個時候肯定只會查找出唯一的一個tab,解構(gòu)第一個就不會有問題。
搜索條件除了上述之外,還有下面可以選擇:
參數(shù) | 類型 | 作用 |
active | boolean | 是否處于激活狀態(tài) |
audible | boolean | 是否處于播放音頻狀態(tài) |
currentWindow | boolean | 是否處于腳本所在窗口內(nèi) |
groupId | number | 是否處于某個分組內(nèi) |
highlighted | boolean | 是否處于高亮狀態(tài) |
index | number | 窗口從左往右第index個tab |
pinned | boolean | 是否處于被固定的狀態(tài) |
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的時候,選擇固定在最左側(cè)的標(biāo)簽,并且可以固定多個。
該api默認(rèn)支持,需要額外的manifest配置,需要顯式聲明“tabs”的permissions
我們可以很方便的給指定的tab發(fā)送消息,一般來說我們可以在content腳本中做消息的監(jiān)聽,接收到消息后使其執(zhí)行不同的業(yè)務(wù)邏輯。
chrome.tabs.sendMessage(
tabId: number, // 目標(biāo)tab的id
message: any, // 發(fā)送信息
options?: object, // 其他配置項
callback?: function, // 回調(diào)函數(shù) )
上面這個是V3版本的插件使用的,在V2版本中我們使用chrome.tabs.sendRquest()
// 在v3版本中已廢棄
chrome.tabs.sendRequest(
tabId: number, // 目標(biāo)tab的id
request: any, // 發(fā)送信息
callback?: function, // 回調(diào)函數(shù)
)
如果我們希望修改一個tab的一些參數(shù)信息,我們可以選擇使用下面這個API:
chrome.tabs.update( tabId?: number, updateProperties: object, callback?: function, )
其中updateProperties的值就是上面提到的queryOptions的屬性保持一致,例如我們可以動態(tài)的更改指定tab的title、url、pinned等狀態(tài)屬性!
當(dāng)我們按住ctrl的同時再滑動鼠標(biāo)滾輪的話就可以調(diào)整頁面的縮放比例,這個可能大家平時都深有體會,但是實際上這個也可以通過插件給我們提供的API來動態(tài)的進(jìn)行調(diào)整:
chrome.tabs.setZoom( tabId?: number, zoomFactor: number, // 縮放比例 callback?: function, )
我們介紹的第一個API就展示了如何創(chuàng)建一個新的tab,他會默認(rèn)創(chuàng)建在最末尾,也就是最右側(cè),如果這個放置位置我們不滿意,我們也可以將其放置在我們想要的位置。
移動
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 // 是否繞過本地緩存 默認(rèn)不繞過,也就是使用本地緩存。 }
我們可以通過插件來控制一個tab的前進(jìn)后退(如果他們都曾有過跳轉(zhuǎn)的記錄)
chrome.tabs.goBack( // 回到最近的一次歷史記錄 tabId?: number, callback?: function, ) chrome.tabs.goForward( // 去到下一個歷史記錄,如果有的話 tabId?: number, callback?: function, )
當(dāng)我們的tab開的特別多的時候,瀏覽器會有個小優(yōu)化,對于某些長時間不用的tab,瀏覽器會清空內(nèi)存中對其的狀態(tài)存貯,因此當(dāng)我們再次將其激活時會重新加載!這個過程插件也提供了API可以幫助我們做到:
chrome.tabs.discard( tabId?: number, callback?: function, ) chrome.tabs.duplicate( // 這個API與discard相反,可以幫助我們復(fù)制一個一摸一樣的tab標(biāo)簽 tabId: number, callback?: function, )
如果我們希望將某些具備相似特征的網(wǎng)站分成一個組,使其能夠在視圖上更好的被察覺,那么我們就可以通過插件為我們提供的API來進(jìn)行實現(xiàn):
第一步:篩選出希望分到同一組的tabs
const tabs=await chrome.tabs.query({ url: [ "https://developer.chrome.com/*"], });
根據(jù)前面的知識,我們很容易就可以知道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 // 希望分組被創(chuàng)建在那個窗口, 默認(rèn)是腳本所在窗口 } }
額外的話:
如果我們希望在分組上再加上一個樣式或者字樣作為標(biāo)記的話,也可以這樣做:
// 第一步: 在manifest.json中添加“tabGrpups”的權(quán)限 { ... "permissions":[ "tabGroups" ] } //第二步: chrome.tabGroups.update(group, { title: "這是分組1" , color:'red' });
就可以修改這個分組的一些特征,上面是增加了一個標(biāo)題,效果如下:
以上我們介紹了基本的API,接下來我們通過一些案例來實際感受一下每個API的作用:
準(zhǔn)備以下的項目:
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插件創(chuàng)建的頁面</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>創(chuàng)建新的頁面</h1> <button id="create-tab">創(chuàng)建</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>是否屬于當(dāng)前窗口:</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>查找結(jié)果:</div> <div id="search-result"></div> </div> </section> <section> <h1>發(fā)送消息</h1> <input type="color" id="send-value" /> <button id="send-btn">變色吧</button> </section> <section> <h1>刪/改/移/丟棄/復(fù)制</h1> <div> <input type="text" id="move-index" /> <button id="move">移動當(dāng)前的tab</button> </div> <div> <button id="remove">移除當(dāng)前的tab</button> </div> <div> <button id="reload">刷新當(dāng)前的tab</button> </div> <div> <input type="text" id="discard-value" /> <button id="discard">丟棄</button> </div> <div> <button id="duplicate">復(fù)制</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">調(diào)整</button> </div> </section> <section> <h1>分組</h1> <div> <input type="text" id="group-title" /> <button id="group">使用查詢的結(jié)果進(jìn)行分組</button> </div> </section> <section> <h1>導(dǎo)航</h1> <div> <button id="goForward">前進(jìn)</button> <button id="goBack">前進(jìn)</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哈!。
下面是我本地的測試效果:
創(chuàng)建頁面/發(fā)送消息
查詢
刪/改/更新
分組
有了以上的武器,就可以玩轉(zhuǎn)tabs啦!一起開始開發(fā)chrome插件吧!
以下是我的其他文章,歡迎閱讀
保姆級講解JS精度丟失問題(圖文結(jié)合)
shell、bash、zsh、powershell、gitbash、cmd這些到底都是啥?
從0到1開發(fā)一個瀏覽器插件(通俗易懂)
用零碎時間個人建站(200+贊)
另外我有一個自己的網(wǎng)站,歡迎來看看 new-story.cn
創(chuàng)作不易,如果您覺得文章有任何幫助到您的地方,或者觸碰到了自己的知識盲區(qū),請幫我點贊收藏一下,或者關(guān)注我,我會產(chǎn)出更多高質(zhì)量文章,最后感謝您的閱讀,祝愿大家越來越好。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。