最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

數(shù)棧技術(shù)干貨:從0到1實現(xiàn)谷歌插件開發(fā)探索及應(yīng)用

2021-05-25 19:07 作者:袋鼠云  | 我要投稿

本文整理自:技術(shù)干貨丨谷歌插件開發(fā)探索及其應(yīng)用

數(shù)棧是云原生—站式數(shù)據(jù)中臺PaaS,我們在github和gitee上有一個有趣的開源項目:FlinkX,記得給我們點個star!star!star!

gitee開源項目:https://gitee.com/dtstack_dev_0/flinkx

github開源項目:https://github.com/DTStack/flinkx

FlinkX是一個基于Flink的批流統(tǒng)一的數(shù)據(jù)同步工具,既可以采集靜態(tài)的數(shù)據(jù),比如MySQL,HDFS等,也可以采集實時變化的數(shù)據(jù),比如MySQL binlog,Kafka等,是全域、異構(gòu)、批流一體的數(shù)據(jù)同步引擎,大家如果有興趣,歡迎來github社區(qū)找我們玩~

一、前言

筆者之前一直想了解一些關(guān)于谷歌插件的相關(guān)知識,希望通過谷歌插件可以更好的認識到谷歌的調(diào)試工具,同時也想著可以使用谷歌插件去寫一些小工具,既學(xué)習了新的東西,又有一定的趣味性。恰逢近段時間需要分享,因此花了兩周時間學(xué)習和了解谷歌插件相關(guān)知識,本篇文章就將筆者在學(xué)習過程中的一些思考分享給大家。當然,因為時間的原因,如果筆者對于這一塊的認識有不對的地方,歡迎批評指正~

二、什么是谷歌插件

下面先介紹一下谷歌插件的主要組成部分,因為目前谷歌插件使用比較普遍的版本為 2.0 版本,因此本文都是基于 2.0 版本進行使用說明,3.0 版本相較于 2.0 版本更為簡便,感興趣的同學(xué)可以點擊文章末尾處的鏈接了解更多相關(guān)知識。

(一)配置文件

谷歌插件的核心文件就是配置文件--manifest.json(清單)文件。
其中,manifest.json 文件最基本的 Api 如下:

{ ? ?"name": "chrome extension", ? ?"version": "1.0.0", ? ?"manifest_version": 2, ? ?"description": "A litlle chrome extension demo" }

主要是包含所寫谷歌插件的名稱、版本以及相關(guān)描述,其中 manifest_version 表示清單文件版本。
manifest.json 作為谷歌插件的核心部分,筆者認為該文件對插件來說就相當于一個入口配置文件,開發(fā)人員只需要在這個文件通過配置相應(yīng)的 js,調(diào)用谷歌瀏覽器提供的 Api,就能實現(xiàn)達到完善這個插件的目的。

1、基本使用Api

在清單文件中有 許多的Api,筆者就不一一列舉了,下面為大家介紹幾個筆者認為比較重要的 Api,通過以下幾個 Api 的介紹,希望可以使讀者對于谷歌插件的開發(fā)過程有一個大概的認識。

1)browser_action

{ ? ?... ? ?"browser_action": { ? ? ? ?"default_icon": { ? ? ? ? ? ?"16": "images/get_started16.png", ? ? ? ? ? ?"32": "images/get_started32.png" ? ? ? ?}, ? ? ? ?"default_title": "谷歌劃詞翻譯", ? ? ? ?"default_popup": "popup.html" ? ?}, ? ?... }

browser_action可設(shè)置瀏覽器右上角的圖標及名稱。
default_popup 可配置點擊圖標后會出現(xiàn)的一個小窗口,這里可以做一些臨時性的操作


2)permissions

{ ? ?... ? ?"permissions": [ "activeTab", "storage", "tabs", "contextMenus" ], ? ? ? ?... }

permissions 可配置谷歌插件權(quán)限申請,如 contextMenus(右鍵菜單)、 tabs(標簽)和storage(插件本地存儲)。

3)content_scripts

{ ? ?... ? ?"content_scripts": { ? ? ? ?"matches": ["<all_urls>"], ? ? ? ?"css": ["content/content_script.css"], ? ? ? ?"js": ["content/content_script.js"] ? ?}, ? ? ? ?... }

content-scripts其實就是谷歌插件中向頁面注入腳本的一種形式(雖然名為 script,其實還可以包括 CSS 的),借助 content-scripts 可以實現(xiàn)通過配置的方式輕松向指定頁面注入 JS 和 CSS。

4)background

{ ? ?··· ? ?"background": { ? ? ? ?"scripts": ["background.js"], ? ? ? ?"persistent": false ? ?}, ? ?··· }

background 是一個常駐的頁面,它的生命周期是插件中所有類型頁面中最長的,它隨著瀏覽器的打開而打開,隨著瀏覽器的關(guān)閉而關(guān)閉,所以通常把需要一直運行的、啟動就運行的及全局的代碼放在 background 里面。

筆者也畫了一個上面涉及到的腳本在瀏覽器中的分布,如下圖:


以上就是筆者認為比較重要的一些Api,在介紹完之后,感興趣的同學(xué)就可以開始著手寫幾個簡單的工具,用來實現(xiàn)自己遠大的抱負以及理想,升華自己高貴的靈魂。

一些同學(xué)可能不太知道開發(fā)谷歌插件的前置條件,在這里為大家簡單介紹下。

首先需要打開管理擴展程序,打開開發(fā)者模式。

點擊加載已解壓的程序按鈕即可加載本地谷歌插件,開發(fā)的時候代碼如果有更新的話,需要刷新已加載插件,點擊關(guān)閉后再開啟,不必刷新開發(fā)頁面。

在了解完前置條件后,筆者將在下文中為大家分享谷歌劃詞翻譯插件從0-1的實現(xiàn)過程,通過開發(fā)這個工具也可以加深對于大家谷歌插件的認識。

三、谷歌劃詞翻譯插件

谷歌翻譯算是筆者使用比較頻繁的插件,對于在網(wǎng)頁上看到的不懂的英文單詞或者句子,直接使用鼠標選中,輕松快捷的翻譯出相應(yīng)的中文。因此在學(xué)習的過程中,筆者就在想谷歌瀏覽器插件的翻譯工具是如何實現(xiàn)的呢?

(一)思考

如何去做一個劃詞翻譯插件,首先要考慮的有以下幾點:

  • 如何實現(xiàn)翻譯效果

  • 如何選中我們需要的元素

  • 選中元素之后如何展示劃詞翻譯面板

  • 所有的瀏覽器 Tab 都需要支持翻譯效果

思考完上面的這些點后,帶著這幾個疑惑,筆者將在下文一一解答,同時也列舉一下遇到的一些點。

(二)劃詞翻譯面板

首先不去考慮該插件的功能,先寫下劃詞翻譯的面板的樣式,所達到的效果如下:


HTML 代碼如下:

<div class="translate-panel show"> ? ?<header>谷歌劃詞翻譯插件<span class="close">X</span></header> ? ?<main> ? ? ? ?<div class="source"> ? ? ? ? ? ?<div class="title">英文</div> ? ? ? ? ? ?<div class="content">test</div> ? ? ? ?</div> ? ? ? ?<div class="result"> ? ? ? ? ? ?<div class="title">簡體中文</div> ? ? ? ? ? ?<div class="content">...</div> ? ? ? ?</div> ? ?</main> </div>

將上面的樣式簡單寫好之后,開始考慮如何將劃詞翻譯的面板展示在瀏覽器當前頁面。對于谷歌瀏覽器來說,在網(wǎng)頁上進行的交互是屬于 content_scripts 的,需要引入劃詞翻譯面板所需要的 JS 或者 CSS來生成當前面板。

其次,在配置文件中配置 content_scripts引入 JS 文件,動態(tài)的生成 DOM 元素。大致的思路就是通過監(jiān)聽到鼠標松開后,去生成翻譯面板,在生成的元素上面添加 opacity 樣式控制顯隱,使用谷歌免費翻譯 Api 進行翻譯。

其中代碼如下所示:

// manifest.json { ? ?... ? ?"content_scripts": { ? ? ? ?"matches": ["<all_urls>"], ? ? ? ?"css": ["content_script.css"], ? ? ? ?"js": ["content_script.js"] ? ?}, ? ?"permissions": [ ? ? ? ?"activeTab" ? ?], ? ?... } // content_script.js class TranslatePanel { ? ?createPanel = () => { ? ? ? ?let wrapper = document.createElement('div') ? ? ? ?wrapper.innerHTML = ` ? ? ? ? ? ?<header>谷歌劃詞翻譯插件<span class="close">X</span></header> ? ? ? ? ? ?<main> ? ? ? ? ? ? ? ?<div class="source"> ? ? ? ? ? ? ? ? ? ?<div class="title">英文</div> ? ? ? ? ? ? ? ? ? ?<div class="content">test</div> ? ? ? ? ? ? ? ?</div> ? ? ? ? ? ? ? ?<div class="result"> ? ? ? ? ? ? ? ? ? ?<div class="title">簡體中文</div> ? ? ? ? ? ? ? ? ? ?<div class="content">...</div> ? ? ? ? ? ? ? ?</div> ? ? ? ? ? ?</main> ? ? ? ?` ? ? ? ?wrapper.classList.add('translate-panel') ? ? ? ?wrapper.querySelector('.close').onclick = () => { ? ? ? ? ? ?this.wrapper.classList.remove('show') ? ? ? ?} ? ? ? ?document.body.appendChild(wrapper) ? ? ? ?this.wrapper = wrapper ? ?} ? ?showPanel = () => { ? ? ? ?this.wrapper.classList.add('show') ? ?} ? ?translateSelect = (content) => { ? ? ? ?const source = this.wrapper.querySelector('.source .content') ? ? ? ?const result = this.wrapper.querySelector('.result .content') ? ? ? ?source.innerHTML = content ? ? ? ?result.innerHTML = '翻譯中...' ? ? ? ?fetch(`https://translate.google.cn/translate_a/single?client=at&sl=en&tl=zh-CN&dt=t&q=${content}`) ? ? ? ? ? ?.then(res => res.json()) ? ? ? ? ? ?.then(res => { ? ? ? ? ? ? ? ?result.innerHTML = res[0][0][0] ? ? ? ? ? ?}) ? ?} ? ?locationPanel = (target) => { ? ? ? ?this.wrapper.style.top = target.y + 'px' ? ? ? ?this.wrapper.style.left = target.x + 'px' ? } } let panel = new TranslatePanel() panel.createPanel() window.onmouseup = (target) => { ? ?// 獲取選中內(nèi)容 ? ?const content = window.getSelection().toString().trim() ? ?if (!content) return ? ?panel.locationPanel({ x: target.pageX, y: target.pageY }) ? ?panel.translateSelect(content) ? ?panel.showPanel() }

在上面過程的中,筆者使用了谷歌免費的翻譯接口,但是這個接口按照目前的設(shè)置還是有一點問題,我們暫時不表?,F(xiàn)在劃詞翻譯的面板就已經(jīng)基本寫好了。

(三)腳本通信

劃詞翻譯插件開發(fā)到這里,細心的同學(xué)應(yīng)該發(fā)現(xiàn)了,每次選中單詞時都會觸發(fā)劃詞翻譯功能,此時急需一個控制翻譯功能的開關(guān),這個開關(guān)就可以放在 popup 腳本上面。

具體的樣式的實現(xiàn)就不去介紹了,主要看一下 HTML 結(jié)構(gòu):

<div class="switch-wrapper"> ? ?<div class="switch-desc">是否啟用劃詞翻譯</div> ? ?<input type="checkbox" class="switch" /> </div>

基本效果如下:


此時面板和劃詞翻譯的面板都已經(jīng)有了,再考慮一下如何實現(xiàn) popup 腳本與 content_script 腳本之間的通信。首先,在
popup 腳本,我們在打開窗口的時候需要去查詢是否有存儲開啟劃詞翻譯的狀態(tài),同時,
同時當狀態(tài)發(fā)生變更的時候需要將其存儲時,再在當前的Tab下面發(fā)送請求。

// popup.js let switchWrapp = document.querySelector('.switch') chrome.storage.sync.get(['checked'], (target) => { ? ?if (target) { ? ? ? ?switchWrapp.checked = target.checked ? ?} }) switchWrapp.onclick = (e) => { ? ?chrome.storage.sync.set({ checked: e.target.checked }) ? ?chrome.tabs.query( {active: true, currentWindow: true }, (tabs) => { ? ? ? ?chrome.tabs.sendMessage(tabs[0].id, { checked: e.target.checked }) ? ?}) }

上面代碼中的 chrome.storage 可用于存儲數(shù)據(jù),追蹤數(shù)據(jù)。storage.sync 的作用是讓谷歌瀏覽器的數(shù)據(jù)同步,這使得在不同 Tab 頁上面切換的狀態(tài)也是可以同步的,同時也不用將數(shù)據(jù)保存在 background 后臺頁面中,storage還有很多Api比如監(jiān)聽 storage數(shù)據(jù)變化的onChanged,這里就不一一介紹了。

將開啟或關(guān)閉劃詞翻譯的狀態(tài)發(fā)送后,content_script.JS 需要添加監(jiān)聽事件,獲取到該狀態(tài)后,進行關(guān)閉或開啟操作。

// content_script.js let checked = false window.onmouseup = (target) => { ? ?··· ? ?if (!content || !checked) return ? ?··· } chrome.storage.sync.get(['checked'], (target) => { ? ?if (target) checked = target.checked }) chrome.runtime.onMessage.addListener((target) => { ? ?if (target) { ? ? ? ?checked = target.checked ? ?} })

在開發(fā)過程中,發(fā)現(xiàn)在當前的 Tab 是可以去完成這個操作的,但是當開啟了多個 Tab 的情況下就會出現(xiàn)開啟翻譯卻不能展示翻譯面板的情況。

針對以上情況筆者思考了一下,此時應(yīng)該將checked儲存起來,不應(yīng)該放在 content_script 腳本當中。

// content_script.js let panel = new TranslatePanel() panel.createPanel() window.onmouseup = (target) => { ? ?// 獲取選中內(nèi)容 ? ?const content = window.getSelection().toString().trim() ? ?if (!content) return ? ?window.chrome.storage.sync.get(['checked'], (result) => { ? ? ? ?if (result.checked) { ? ? ? ? ? ?panel.locationPanel({ x: target.pageX, y: target.pageY }) ? ? ? ? ? ?panel.translateSelect(content) ? ? ? ? ? ?panel.showPanel() ? ? ? ?} ? ?}) } chrome.runtime.onMessage.addListener((target) => { ? ?if (target.type == 'CHECKED') { ? ? ? ?chrome.storage.sync.set({ checked: target.checked }) ? ?} })

以上,popup 腳本和 content_script 腳本之間就實現(xiàn)了通信,翻譯插件也可以通過 popup 上面的按鈕,進行開啟或關(guān)閉翻譯功能。

同理,也可以知道其他模塊也是可以通過這種方式去進行通信,不同的是其他腳本向 content_script 通信是需要使用 tabs,先查找到當前的 Tab 在發(fā)送請求。

(四)右鍵直達翻譯頁面

當關(guān)閉劃詞翻譯的時候,直接無法翻譯選中內(nèi)容也不是很友好,這個時候可以設(shè)置為點擊右鍵的時候出現(xiàn)翻譯菜單項。因為這部分內(nèi)容需要一直存在就加在 background 中。

// backgrond.js // 當擴展程序第一次安裝、更新至新版本或 Chrome 瀏覽器更新至新版本時產(chǎn)生 chrome.runtime.onInstalled.addListener(() => { ? ?chrome.contextMenus.create({ ? ? ? ?"id": "SELECT_TRANSLATE", ? ? ? ?"title": "翻譯 %s", ? ? ? ?"contexts": ["selection"] ? ?}) }) chrome.contextMenus.onClicked.addListener((target) => { ? ?if (target.menuItemId == 'SELECT_TRANSLATE') { ? ? ? ?chrome.tabs.create({url: `https://translate.google.cn/?sl=en&tl=zh-CN&text=${target.selectionText}&op=translate`}) ? ?} })

(五)跨域問題

開發(fā)過程中,有的同學(xué)也看出來了一個問題,比如說谷歌的這個翻譯的 Api 需要同源的情況下才能正常調(diào)用該接口,然后就只能在谷歌翻譯的頁面中使用劃詞翻譯,場面一度十分尷尬...

那么,正常來說這個劃詞翻譯使用起來也是十分不合理的,接下來就需要解決一下這個跨域的問題。

筆者當時想要嘗試的是使用 JSONP,也就是去使用嵌入腳本去進行跨域,發(fā)現(xiàn)還是會有一些問題,主要是谷歌的翻譯的接口不支持回調(diào)函數(shù)。

同時也去查閱了一些資料,發(fā)現(xiàn)是可以在 content_script 中通知 background,background 后臺去調(diào)用谷歌翻譯的 Api 是來避免這個情況的。

主要因為 background 的權(quán)限非常高,幾乎可以調(diào)用所有的 Chrome 擴展 Api,而且它可以無限制跨域,也就是可以跨域訪問任何網(wǎng)站而無需要求對方設(shè)置 CORS。

具體添加的代碼如下:

// content_script.js translateSelect = (content) => { ? ?const source = this.wrapper.querySelector('.source .content') ? ?const result = this.wrapper.querySelector('.result .content') ? ?source.innerHTML = content ? ?result.innerHTML = '翻譯中...' ? ?chrome.runtime.sendMessage({ type: 'QUERY_TRANSLATE', queryContent: content }, (res) => { ? ? ? ?result.innerHTML = res[0][0][0] ? ?}) } // background.js chrome.runtime.onMessage.addListener((request, sender, callBack) ?=> { ? ?if (request.type == 'QUERY_TRANSLATE') { ? ? ? ?fetch(`https://translate.google.cn/translate_a/single?client=at&sl=en&tl=zh-CN&dt=t&q=${request.queryContent}`) ? ? ? ? ? ?.then(res => res.json()) ? ? ? ? ? ?.then(res => { ? ? ? ? ? ? ? ?callBack(res) ? ? ? ? ? ?}) ? ? ? ?return true ? ?} })

background 中的發(fā)送消息的監(jiān)聽事件返回 true 是為了與 content_script 的消息通道保持打開,通過異步的方式發(fā)送請求。

現(xiàn)在想想,如果使用插件的 background 就可以去跨域去進行請求一些借口,使用不得當?shù)脑捀杏X還是很危險的,可以去獲取其他網(wǎng)站的一些信息,由此可見,還是要慎重的進行此操作。

(六)待完善的點

  • 支持其他語言的翻譯,谷歌翻譯的接口有兩個 Api,sl(文本翻譯之前的語言) 和 tl(文本需要翻譯成的語言) 可通過改變對應(yīng)的值支持其他語言的翻譯;

  • 樣式完善,實現(xiàn)先選中圖標在進行翻譯。多添加一步感覺對交互更友好,不用去進行開關(guān)的操作。

代碼結(jié)構(gòu)

介紹完了劃詞翻譯插件,筆者原本是打算再分享一個關(guān)于谷歌 devtool 開發(fā)工具,開發(fā)一個類似于 React Developer Tools 的本地開發(fā)工具,但是由于時間也是不太夠,涉及到的點比較多,同時查閱了很多的資料對于這一塊的介紹也是比較的淺,所以還是決定著重于介紹劃詞翻譯。

相信通過劃詞翻譯的開發(fā)能使得讀者比較快速的認識到谷歌插件,除了谷歌插件外,如果對于 devtool 工具插件開發(fā)有興趣的同學(xué)也可以去了解一下。

另外,有的同學(xué)可能會認為目前開發(fā)的效率是有一點低的,現(xiàn)在的話谷歌插件的開發(fā)也是可以基于 react + antd 去進行開發(fā)的,也是可以達到高效快速的去開發(fā)一個插件的效果。

四、結(jié)尾

在學(xué)習谷歌插件的時候,筆者遇到了一些問題,比如說文檔比較少,官方文檔又是英文的還經(jīng)常 404,不過呢,好在谷歌瀏覽器有提供了很多 Api,筆者這邊在寫插件的時候也感覺到了很多趣味性。本篇文章還是寫的比較通俗易懂,如果有什么點寫的不對或著不清晰的地方,歡迎大家留言進行探討。

相關(guān)資源及參考:

  • 官方文檔:https://developer.chrome.com/docs/extensions/mv3/

  • react + antd 腳手架:https://github.com/jhen0409/react-chrome-extension-boilerplate

  • 谷歌翻譯插件完整代碼:https://github.com/ting0130/chrome-extensions-translate


數(shù)棧技術(shù)干貨:從0到1實現(xiàn)谷歌插件開發(fā)探索及應(yīng)用的評論 (共 條)

分享到微博請遵守國家法律
秦安县| 明光市| 台前县| 崇义县| 玛纳斯县| 福清市| 张北县| 绥棱县| 江川县| 栖霞市| 神木县| 昌都县| 长顺县| 甘肃省| 吴忠市| 和林格尔县| 原阳县| 钟祥市| 资溪县| 珠海市| 汶上县| 龙江县| 砀山县| 乐陵市| 东丰县| 宁陕县| 麻城市| 平邑县| 柳江县| 南昌市| 寻乌县| 田林县| 肇源县| 龙井市| 乌兰察布市| 玛纳斯县| 开鲁县| 海丰县| 崇礼县| 大宁县| 安丘市|