44

chrome扩展程序初体验

 5 years ago
source link: https://www.tuicool.com/articles/fMj6fmB
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

常被称为chrome插件,虽然名称定语为chrome,但是chrome扩展程序除了在chrome浏览器上使用,理论上还可以运行在wekit内核的浏览器上(毕竟chrome已经和webkit分道扬镳开始走Blink内核了)

chrome扩展主要是 增强浏览器的功能 ,能定制个人专属的浏览器不是很有意思:smirk:

用chrome扩展可以对页面原有DOM进行修改,比如本例是对大搜车全体开发人员的语雀个人中心进行扩展,在原页面的基础上将开发人员的日常动态集中在一个页面中,包括gitlab的git热力图。直接重写整个页面的成本过大,所以就用chrome扩展对原页面进行二次修改,并能避免第三方接口跨域的问题。

上述情景包括Chrome扩展的开发,嵌入的iframe页面的开发,下面主要写的是chrome开发总结,适合chrome开发新手。

入门须知:

chrome扩展程序的主要组成:

  • manifest.json // 说明整个程序的配置,必选 (具体各配置项参考 官方配置API文档
  • background.js // 后台脚本,默认持续运行在后台的脚本
  • content.js // 内容脚本,注入到匹配吻合页面的脚本
  • popup.html // 扩展图标点击查看的视图窗

脚本类型

注入到原网页上下文的脚本

与原页面自带脚本同等的脚本,可以访问原页面脚本中的所有变量,这种脚本只能使用网页的通用API,无法使用chrome扩展提供的API,使用时需要在mainfest.js中配置web-accessible-resources,表明扩展程序的某些脚本可以从网页访问

"web_accessible_resources": [
    "js/sideTag.js"
]

重新载入,不属于扩展程序的脚本

content脚本

注入到匹配的当前页面中的脚本,但是并不能完成融入到当前页面的脚本中,而是运行在一个被隔离的环境中,能共享当前页面的DOM对象,但无法获取当前页面的全部数据,例如当前页面脚本中的变量数据,在这种脚本中可以使用部分chrome扩展的API,可以用来解决跨域问题(后文详解),在mainfest中配置content

"content_scripts": [{
    "matches": ["*://souche.yuque.com/*"],
    "js": ["modifyDom.js"],
    "run_at": "document_end"
}]

重新载入,不完全属于扩展程序的脚本

background脚本

运行在后台的脚本,与当前浏览页面无关,但是这类脚本可以保持持续运行或者活动时运行,持续运行在浏览器页面打开到关闭的时间里,活动状态运行为一种非持续运行后台脚本,可以在不活动状态释放占用的资源,提高性能;后台脚本可以使用全部的chrome扩展API,在mainfest中配置background

"background": {
    "scripts": ["background.js"],
    "persistent": false 
    // true表明持续运行,false非持续运行
}

在非持续运行时,每次页面活动会触发重新载入,持续运行时加载一次,完全属于扩展程序的脚本

popup脚本

也就是我们常见的在点击扩展图标时弹出的视图窗口,它和background脚本一样可以使用全部的chrome扩展API,一般会用来用户授权,但是最好在用户授权之后将授权信息保存在本地,不然每次打开都需要用户授权就很不友好了(这次没实现popup,只能说说我所了解的),在mainfest中配置popup

"browser_action" : {
    "default_title" : "搜车KM",
    "default_popup" : "popup.html",
    "default_icon" : {
      "16" : "KM.png"
    }
}

用户每次点击图标都会重新载入脚本,完全属于扩展程序的脚本

再往下分析一下实践中一定会碰到的通信和跨域问题,毕竟这些坑都踩了--

通信问题

注入脚本与原页面脚本:

可以从注入脚本中获取到原页面脚本的变量,通过window.addEventListener和 window.postMessage来实现,例如获取window对象中的特殊属性,:chestnut:

// 注入脚本 sideTag.js
window.postMessage({ "sLogin": window.appData.me.login }, '*');  
// 内容脚本 modifyDom.js
var sLogin = '';  
window.addEventListener("message", function (event){  
if (event.data.sLogin) {  
        sLogin = event.data.sLogin
    }
}, false);

之前为了获取原页面的window.appData数据,用了一种很ZZ的方法——模版字符串,能实现,但是代码看起来真的累啊。。。来个对比吧 -_-|

// 内容脚本使用模版字符串code jAvqyi6.png!web // 内容脚本引用code em6Nbqa.png!web // 注入脚本code yqieaeN.png!web

PS: 同一个扩展程序的不同注入脚本是运行在同一个上下文的,注意变量不要重复声明

内容脚本与“完全属于扩展程序脚本”的通信:

这两者之前是可以互通消息的,内容脚本可以调用chrome.runtime的API,后者可以调用chrome.*的全部API,只是两者作为发送方时发送的方式不一样

// 内容脚本 modifyDom.js
chrome.runtime.sendMessage(  
    {
        type: 'get',
        url: 'https://skm.souche.com/user/' + urlParam // 需要请求的url
    },
    response => {
        // ...
    }
)
​
// 后台脚本 background.js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {  
  chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
    // ...
  });
});

接收方的方法一致,:chestnut:

// 后台脚本 background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {  
  if (request.type == 'get') {
    fetch(request.url)
      .then(response => {
        if (response.status === 200) return response.text()
        else if (response.status === 401) {
          return Promise.resolve(response.status)
        }
      })
      .then(text => {
        sendResponse(text)
      })
      .catch(error => console.error('error', error))
    return true // 异步
  }
})

“完全属于扩展程序脚本”之间的通信:

他们之间函数是可以直接互相访问的,并且可以互相访问对方的DOM元素;所以他们之间事实上不存在什么复杂的通信

跨域问题

跨域感觉是使用chrome扩展的大收益,毕竟有些第三方API不允许服务端直接跨域请求啊。。。

在扩展脚本中使用XHR发起跨域请求,第三方域名需要在mainfest的permissions中配置一下 ​

"permissions": [
    "*://souche.yuque.com/*",
    "*://skm.souche.com/*",
    "*://git.souche-inc.com/*",
    "*://f2e-assets.souche.com/*"
]

BUT,前不久chrome扩展已经不支持内容脚本中xhr的跨域请求了,开发中的我不得已换了跨域的方法,也就是前面通信中提到的chrome.runtime的调用,在后台脚本中处理内容脚本的外部服务器请求,(此处自行回看上文代码)再将处理后的数据发送给内容脚本,前端同学生活不易啊,说不定一觉起来你的代码就跑不动了。。。

emmm... 介于这个扩展没有发布,只能给大家看一下前后对比图了:sweat_smile:

BJJ7fqu.png!webAjQVZzU.png!web

第一次写chrome扩展,总结的肯定不全面,大佬们多多指导。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK