整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          chrome插件之tabs

          chrome插件之tabs

          、前面的話

          本文主要的內容是幫助讀者朋友梳理chrome插件的tabs能力,如果您是第一次閱讀本文,也建議您在閱讀完本文后,嘗試看看我下面的這些系列文章,它們可以更好的幫您認識和了解chrome插件:

          • chrome插件之從0到1
          • chrome插件之通信(V3版)
          • chrome插件之manifest配置
          • chrome插件之玩轉action

          1.能力

          一款瀏覽器插件具備非常強大的能力,它不僅可以向當前所有的站點里注入腳本,對網站的功能進行擴展。更重要的是它還可以和瀏覽器的標簽系統進行交互,從而創建、修改、管理每一個tab,而這一切都基于插件系統為我們提供的tabs相關的API,chrome不僅提供了我們用于操作和管理tabs的API,而且還提供了和content腳本之間的通信方法。

          溫馨提示:

          Tabs API 只能在background腳本中以及option腳本、popup腳本、由chrome創建的tab中訪問到,在content腳本中是無法訪使用的。

          換句話說,chrome有選擇性的給不同的腳本環境注入了不同的chrome對象,導致提供的API具備差異性。

          該圖是我們在特定環境下可以通過chrome.tabs訪問的所有的api,這些就是chrome為我們內置的提供給開發者的能力

          2.權限

          在之前的文章中我們提到過,如果要使用某些特別的API,我們需要在插件配置文件manifest.json中配置相應的權限聲明,但幸運的是對于tabs相關的部分API不需要在manifest.json中顯式的配置“tabs”就可以直接使用。比如說: 創建一個新的tab,重新加載某個tab,或者導航到另外一個URL等等。

          但是下面的這些API在使用的時候,則需要加上相關的配置才可以使用,比如說:

          • permission
          • 如果你希望通過特定的條件找到某些tabs,你需要使用 chrome.tabs.query(queryInfo , callback) 這個API,這個時候就需要顯示的在manifest.json中permission中添加“tabs”聲明。
          • host permission 如果你希望能夠對指定的tab動態的在其中注入并執行一段腳本,或者注入、移除某一段css樣式,那么你可能需要用到這些API:

          chrome.tabs.executeScript() // 注入一段腳本并執行

          chrome.tabs.insertCss() // 注入一段css樣式

          chrome.tabs.removeCss() // 移除一段css樣式

          • 這個時候就需要在manifest.json中顯式的聲明需要命中的url。

          {

          // manifest.json "host_permissions":[ "<all_urls>" ] // 支持正則匹配正則

          }

          二、API

          接下來我們一一通過案例來認識他們,從而感受每一個API的具體行為以及他們的使用條件、注意事項等等。

          1. 創建

          我們可以通過這個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配置

          2. 查找

          我們可能有這樣的需要,獲取當前瀏覽器窗口處于激活狀態的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

          3.發送消息

          我們可以很方便的給指定的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, // 回調函數

          )

          4.修改

          如果我們希望修改一個tab的一些參數信息,我們可以選擇使用下面這個API:

          chrome.tabs.update( tabId?: number, updateProperties: object, callback?: function, )

          其中updateProperties的值就是上面提到的queryOptions的屬性保持一致,例如我們可以動態的更改指定tab的title、url、pinned等狀態屬性!

          5.縮放比

          當我們按住ctrl的同時再滑動鼠標滾輪的話就可以調整頁面的縮放比例,這個可能大家平時都深有體會,但是實際上這個也可以通過插件給我們提供的API來動態的進行調整:

          chrome.tabs.setZoom( tabId?: number, zoomFactor: number, // 縮放比例 callback?: function, )

          6.移動/移除/刷新

          我們介紹的第一個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 // 是否繞過本地緩存 默認不繞過,也就是使用本地緩存。 }

          7.導航

          我們可以通過插件來控制一個tab的前進后退(如果他們都曾有過跳轉的記錄)

          chrome.tabs.goBack( // 回到最近的一次歷史記錄 tabId?: number, callback?: function, ) chrome.tabs.goForward( // 去到下一個歷史記錄,如果有的話 tabId?: number, callback?: function, )

          8.丟棄/復制

          當我們的tab開的特別多的時候,瀏覽器會有個小優化,對于某些長時間不用的tab,瀏覽器會清空內存中對其的狀態存貯,因此當我們再次將其激活時會重新加載!這個過程插件也提供了API可以幫助我們做到:

          chrome.tabs.discard( tabId?: number, callback?: function, ) chrome.tabs.duplicate( // 這個API與discard相反,可以幫助我們復制一個一摸一樣的tab標簽 tabId: number, callback?: function, )

          9.分組

          如果我們希望將某些具備相似特征的網站分成一個組,使其能夠在視圖上更好的被察覺,那么我們就可以通過插件為我們提供的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

          創作不易,如果您覺得文章有任何幫助到您的地方,或者觸碰到了自己的知識盲區,請幫我點贊收藏一下,或者關注我,我會產出更多高質量文章,最后感謝您的閱讀,祝愿大家越來越好。

          寫Express接下來的內容前,先來一篇輕松點兒的文章,之前我總結過一篇關于nth-child&nth-of-type的文章(還記得那篇文章的結論嗎?對,就是兩句話)。這一篇我依然來處理一個有關CSS的問題。

          說到tab切換,咱們很熟悉,最常用的做法是使用JS處理顯示與隱藏,聽說利用CSS3的偽類選擇器也能實現相同的tab切換效果,于是我就試一把。

          這個方法主要是借助input和checked屬性控制其后面元素的顯示與否,涉及到的需要搞懂的知識點就三個:

          1、nth-of-type的使用

          2、input的id和label的for屬性聯系

          3、在css3中‘~’表示兄弟元素,‘+’表示相鄰元素

          下面是實例區:

          知道了上面這三點,那這個問題就簡單了,先看一下例子的DOM結構:

          從上圖可以看出DOM結構很簡單,但是要注意兩點,第一:input的id和label中的for對應(如tab1),第二:input必須和其內容div.tab在同一級,也就是說它們必須擁有同一個父元素。

          下面看一下本例的重點部分,樣式:

          從樣式代碼上可以看出,當input處理checked時,通過“+”符給label加樣式,使用nth-of-type定位,在通過“~”將對應的內容區設置為display:block。

          如果想讓這個切換看起來更動感,可以使用transition給切換加個動畫。

          寫在最后的總結:

          通過測試,這種方法在IE8下不兼容,這沒關系,因為我們可以在H5開發中用的爽爽的。哈哈

          短內容,說完整事,哪怕只讀一篇也能學知識。點擊關注小鄭搞碼事,說的都是那堆代碼。謝謝您的鼓勵!

          插件安裝方式,ctrl+shift+p輸入install packages

          CSS3:支持CSS3里的語法高亮。(Sublime3里自帶的CSS高亮不夠用)。安裝后, 打開一個CSS文件,然后按照下面GIF操作,將CSS3高亮作為CSS文件的默認高亮。

          livestyle:調試后實時更新頁面。安裝這個還需要安裝谷歌的插件。

          Emmet:快速生成代碼,用過h5build的應該知道。ul*li*3相當于:

          <ul><li></li><li></li><li></li></ul>
          

          記下語法就ok.

          ConvertToUTF8:編碼轉utf8

          CSScomb:css屬性排序

          html5:html規范包,輸入html+tab生成html規范文檔

          Alignment:代碼對齊,快捷鍵ctrl alt a

          Autoprefixer插件:css3私有前綴自動補全插件

          AutoFileName:自動完成文件名的輸入,如圖片選取,快捷輸入文件名路徑補全

          less sass插件

          JsFormat js格式化插件

          Terminal 命令行插件

          Minify 代碼美化壓縮插件

          Color Highlighter 顏色選擇插件

          快捷鍵

          Ctrl+D 選中光標所占的文本,繼續操作則會選中下一個相同的文本。

          Alt+F3 選中文本按下快捷鍵,即可一次性選擇全部的相同文本進行同時編輯。舉個栗子:快速選中并更改所有相同的變量名、函數名等。

          Ctrl+L 選中整行,繼續操作則繼續選擇下一行,效果和 Shift+↓ 效果一樣。

          Ctrl+Shift+L 先選中多行,再按下快捷鍵,會在每行行尾插入光標,即可同時編輯這些行。

          Ctrl+Shift+M 選擇括號內的內容(繼續選擇父括號)。舉個栗子:快速選中刪除函數中的代碼,重寫函數體代碼或重寫括號內里的內容。

          Ctrl+M 光標移動至括號內結束或開始的位置。

          Ctrl+Enter 在下一行插入新行。舉個栗子:即使光標不在行尾,也能快速向下插入一行。

          Ctrl+Shift+Enter 在上一行插入新行。舉個栗子:即使光標不在行首,也能快速向上插入一行。

          Ctrl+Shift+[ 選中代碼,按下快捷鍵,折疊代碼。

          Ctrl+Shift+] 選中代碼,按下快捷鍵,展開代碼。

          Ctrl+K+0 展開所有折疊代碼。

          Ctrl+← 向左單位性地移動光標,快速移動光標。

          Ctrl+→ 向右單位性地移動光標,快速移動光標。

          shift+↑ 向上選中多行。

          shift+↓ 向下選中多行。

          Shift+← 向左選中文本。

          Shift+→ 向右選中文本。

          Ctrl+Shift+← 向左單位性地選中文本。

          Ctrl+Shift+→ 向右單位性地選中文本。

          Ctrl+Shift+↑ 將光標所在行和上一行代碼互換(將光標所在行插入到上一行之前)。

          Ctrl+Shift+↓ 將光標所在行和下一行代碼互換(將光標所在行插入到下一行之后)。

          Ctrl+Alt+↑ 向上添加多行光標,可同時編輯多行。

          Ctrl+Alt+↓ 向下添加多行光標,可同時編輯多行。

          Ctrl+J 合并選中的多行代碼為一行。舉個栗子:將多行格式的CSS屬性合并為一行。

          Ctrl+Shift+D 復制光標所在整行,插入到下一行。

          Tab 向右縮進。

          Shift+Tab 向左縮進。

          Ctrl+K+K 從光標處開始刪除代碼至行尾。

          Ctrl+Shift+K 刪除整行。

          Ctrl+/ 注釋單行。

          Ctrl+Shift+/ 注釋多行。

          Ctrl+K+U 轉換大寫。

          Ctrl+K+L 轉換小寫。

          Ctrl+Z 撤銷。

          Ctrl+Y 恢復撤銷。

          Ctrl+U 軟撤銷,感覺和 Gtrl+Z 一樣。

          Ctrl+F2 設置書簽

          Ctrl+T 左右字母互換。

          F6 單詞檢測拼寫

          Ctrl+F 打開底部搜索框,查找關鍵字。

          Ctrl+shift+F 在文件夾內查找,與普通編輯器不同的地方是sublime允許添加多個文件夾進行查找,略高端,未研究。

          Ctrl+P 打開搜索框。舉個栗子:1、輸入當前項目中的文件名,快速搜索文件,2、輸入@和關鍵字,查找文件中函數名,3、輸入:和數字,跳轉到文件中該行代碼,4、輸入#和關鍵字,查找變量名。

          Ctrl+G 打開搜索框,自動帶:,輸入數字跳轉到該行代碼。舉個栗子:在頁面代碼比較長的文件中快速定位。

          Ctrl+R 打開搜索框,自動帶@,輸入關鍵字,查找文件中的函數名。舉個栗子:在函數較多的頁面快速查找某個函數。

          Ctrl+: 打開搜索框,自動帶#,輸入關鍵字,查找文件中的變量名、屬性名等。

          Ctrl+Shift+P 打開命令框。場景栗子:打開命名框,輸入關鍵字,調用sublime text或插件的功能,例如使用package安裝插件。

          Esc 退出光標多行選擇,退出搜索框,命令框等。

          Ctrl+Tab 按文件瀏覽過的順序,切換當前窗口的標簽頁。

          Ctrl+PageDown 向左切換當前窗口的標簽頁。

          Ctrl+PageUp 向右切換當前窗口的標簽頁。

          Alt+Shift+1 窗口分屏,恢復默認1屏(非小鍵盤的數字)

          Alt+Shift+2 左右分屏-2列

          Alt+Shift+3 左右分屏-3列

          Alt+Shift+4 左右分屏-4列

          Alt+Shift+5 等分4屏

          Alt+Shift+8 垂直分屏-2屏

          Alt+Shift+9 垂直分屏-3屏

          Ctrl+K+B 開啟/關閉側邊欄。

          F11 全屏模式

          Shift+F11 免打擾模式


          主站蜘蛛池模板: 亚洲一区二区三区亚瑟| 无码人妻一区二区三区精品视频 | 极品人妻少妇一区二区三区| 日韩免费无码视频一区二区三区| 色综合一区二区三区| 亚洲av无码片vr一区二区三区| 中文字幕在线无码一区二区三区| 成人毛片一区二区| 精品亚洲AV无码一区二区| 国产成人精品一区二区秒拍 | 日韩精品电影一区亚洲| 在线欧美精品一区二区三区| 日韩欧国产精品一区综合无码| 久久一区二区三区99| 亚洲一区二区精品视频| 国产一区二区三区免费看| 国产精品无码一区二区三区不卡 | 福利电影一区二区| 国产成人精品一区二三区熟女| 国产香蕉一区二区在线网站 | 一区二区三区免费视频观看| 精品国产日韩亚洲一区在线 | 久久久久人妻一区精品 | 国产精品揄拍一区二区| 亚洲一区二区三区四区视频| 亚洲国产一区二区三区青草影视| 国产一区二区中文字幕| 亚洲一区二区电影| 中文精品一区二区三区四区| 麻豆AV天堂一区二区香蕉| 女人18毛片a级毛片一区二区| 麻豆va一区二区三区久久浪 | 中文字幕在线一区二区在线| 3d动漫精品啪啪一区二区中| 亚洲熟女乱色一区二区三区 | 中文字幕一区二区三区精彩视频 | 国产成人久久精品麻豆一区| 又硬又粗又大一区二区三区视频| 亚洲色婷婷一区二区三区| 无码精品国产一区二区三区免费 | 冲田杏梨高清无一区二区|