提到VUE大家都很熟悉,VUE可以做很多东西,包括SPA单页面应用,WEBAPP应用,小程序应用等等,但是你们有没有考虑过过,使用VUE来制作一款抓取网页数据(文字+截屏)的扩展呢?敢想就要敢做,Let's Go !
1. 开发目标:完成一款在POPUP窗口登陆后,在当前网页加载出一个可以获取网页文字信息,以及可以多类型截图的工具,截完图可以下载,最终操作完成后可以直接提交
2. 开发工具:vue、jquery、chrome extension api 、es6 、bootstrap
3. 具体功能:
(1)信息抓取:标题、副标题、内容
(2)截屏:当前窗口截屏、当前整个网页截屏、自定义区域截屏4.
扫描二维码关注公众号,回复:
3354514 查看本文章
4. 最终效果预览:
5. 代码架构逻辑:
(1)页面层:content-script注入当前页面,生成功能框,监听鼠标事件,筛选文字信息,动态改变数据,通过vue动态渲染dom,在发出截屏信息后获取backgroud层发送过来的图片信息
(2)背景层:监听message信息,根据传递过来的值类型,进行多类型截屏,然后将图片数据返回给页面层
6. content-script.js 页面代码逻辑:
(1)抓取页面文字信息
getAllTags(){
var elems = $('#plugin-body').get(0).getElementsByTagName('*');
$('a').removeAttr("href");
for(var i=0;i<elems.length;i++){
elems[i].addEventListener('mousedown',(e)=>{
if(this.focusInputIndex)
this.inputData[this.focusInputIndex] = e.target.innerText;
e.stopPropagation();
e.cancelBubble = true;
})
elems[i].addEventListener('mouseup',(e)=>{
this.cancelText();
e.stopPropagation();
e.cancelBubble = true;
})
elems[i].index = i;
elems[i].onmouseover = function(e){
// 插件边框
for(var j=0;j<elems.length;j++){
if(elems[j] == this){
continue;
}
elems[j].classList.remove('pluginRedBorder');
}
// 添加样式
this.classList.add('pluginRedBorder');
e.stopPropagation();
e.cancelBubble = true;
};
}
}
(2)窗口截屏核心代码:
//content-script.js 发出截屏通知
windowCapture(){
this.isShow = false;
setTimeout(()=>{
chrome.runtime.sendMessage({event:'windowCapture',value:''},(data)=>{
this.defaultImage = data;
this.isShow = true;
});
},200);
}
//background.js 收到通知并且做出截屏操作
chrome.tabs.captureVisibleTab({ format: 'png', quality: 100},(dataUrl)=>{
callback(dataUrl);
});
(3)当前网页全屏截图
//content-script.js 发出全网页截图通知,切传递过去当前的网页信息
webCapture(){
this.isShow = false;
var pageSize = {
scrollHeight: document.body.scrollHeight,
scrollWidth: document.body.scrollWidth,
clientWidth: document.documentElement.clientWidth,
clientHeight: document.documentElement.clientHeight
};
//接收移动页面通知
chrome.runtime.onMessage.addListener(function(message, sender, resCallback){
switch(message.event){
case 'scrollBy':
window.scrollBy(message.value.x,message.value.y);
break;
case 'scrollTo':
window.scrollTo(message.value.x,message.value.y);
default:
break;
}
resCallback({status:true});
})
//发送捕获
setTimeout(()=>{
chrome.runtime.sendMessage({event:'webCapture',value:pageSize},(data)=>{
this.defaultImage = data;
var image = new Image();
image.src = data;
image.onload = function(){
$('body').append(this);
}
this.isShow = true;
});
},200);
}
// background.js 收到通知后分步骤全网页截图
new WebCapture(request.value,callback);
/* 全页面捕捉 */
function WebCapture(v,callback){
this.currentY = 0;
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.sw = v.scrollWidth;
this.sh = v.scrollHeight;
this.cw = v.clientWidth;
this.ch = v.clientHeight;
this.tabId = 0;
this.screenData = '';
this.captureImgData = '';
this.callback = callback;
//初始化相关函数
this.init();
}
WebCapture.prototype = {
constructor: WebCapture,
//初始化方法
init(){
//1. 初始化获取tabId
this.getTabId();
//2. 获取当前tab页面的宽高且初始化canvas的宽高
this.initWH();
},
//获取tabId
getTabId(){
chrome.tabs.getSelected((tab)=>{
this.tabId = tab.id;
//3. 初始化页面位置移动到顶部
this.initPagePosition();
})
},
//初始化canvas的宽高
initWH(){
this.canvas.width = this.sw;
this.canvas.height = this.sh;
},
//初始化页面位置移动到顶部
initPagePosition(){
this.scrollPage('scrollTo',0,0);
},
//向Tab页面发出跳转通知
scrollPage(event,x,y){
chrome.tabs.sendMessage(this.tabId,{event,value:{x,y}},(res)=>{
if(res.status){
//执行绘制
setTimeout(()=>{
this.captureWebPage();
},1000);
}
})
},
//将当前窗口内容转换成 image Data
captureWebPage(){
chrome.tabs.captureVisibleTab((data)=>{
this.screenData = data;
//分阶段绘制canvas
this.drawImage();
})
},
//往Canvas中填充图片
drawImage(){
let img = new Image();
img.src = this.screenData;
img.onload = ()=>{
//绘制到最底部
if(this.currentY + this.ch >= this.sh){
let lastHeight = this.ch - this.sh % this.ch;
let y = 0;
if(this.currentY == 0){
y = 0;
}else{
y = this.currentY - lastHeight;
}
this.ctx.drawImage(img,0,0,this.cw,this.ch,0,y,this.cw,this.ch);
this.getImage();
}else{ //还没有绘制到最底部
this.ctx.drawImage(img,0,0,this.cw,this.ch,0,this.currentY,this.cw,this.ch);
this.currentY += this.ch;
this.scrollPage('scrollBy',0,this.currentY);
}
};
},
//获取到最终的图片
getImage(){
this.captureImgData = this.canvas.toDataURL('image/png');
this.callback(this.captureImgData);
}
}
(4)自定义区域拖拽截屏
//content-script.js 发出自定义区域截屏通知,切传递过去当前的网页信息
//区域截屏
areaCapture(){
var that = this;
this.isShow = false;
var pageSize = {
clientWidth: document.documentElement.clientWidth,
clientHeight: document.documentElement.clientHeight,
x:0,
y:0,
width:0,
height:0
};
var xmlns = 'http://www.w3.org/2000/svg';
var dom = document.createElementNS(xmlns,'svg');
var rect = document.createElementNS(xmlns,'rect');
dom.setAttribute('class','captureScreenBox');
dom.setAttribute('width',pageSize.clientWidth);
dom.setAttribute('height',pageSize.clientHeight);
dom.setAttribute('viewBox',`0 0 ${pageSize.clientWidth} ${pageSize.clientHeight}`);
dom.setAttribute('xmlns',xmlns);
$(dom).append(rect);
//点击拖拽自定义选区
$(dom).on('mousedown',(e)=>{
var x1 = e.clientX;
var y1 = e.clientY;
var x2 = 0;
var y2 = 0;
rect.setAttribute('x',x1);
rect.setAttribute('y',y1);
$(dom).on('mousemove',(e)=>{
x2 = e.clientX;
y2 = e.clientY;
rect.setAttribute('width',Math.abs(x1-x2));
rect.setAttribute('height',Math.abs(y1-y2));
pageSize = Object.assign({},pageSize,{x:x1,y:y1,width:Math.abs(x1-x2),height:Math.abs(y1-y2)})
});
$(dom).on('mouseup',(e)=>{
sendMessage();
$(dom).hide();
$(dom).off();
})
});
//发出生成图片的通知
function sendMessage(){
chrome.runtime.sendMessage({event:'areaCapture',value:pageSize},(data)=>{
that.defaultImage = data;
var image = new Image();
image.src = data;
image.onload = function(){
$('body').append(this);
}
that.isShow = true;
});
}
$('body').append(dom);
}
// background.js 收到通知后进行自定义区域截屏
new AreaCapture(request.value,callback);
function AreaCapture(v,callback){
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.cw = v.clientWidth;
this.ch = v.clientHeight;
this.vw = v.width;
this.vh = v.height;
this.offsetX = v.x;
this.offsetY = v.y;
this.tabId = 0;
this.screenData = '';
this.captureImgData = '';
this.callback = callback;
//初始化相关函数
this.init();
}
AreaCapture.prototype = {
constructor: AreaCapture,
//初始化方法
init(){
//1. 初始化获取tabId
this.getTabId();
//2. 获取当前tab页面的宽高且初始化canvas的宽高
this.initWH();
},
//获取tabId
getTabId(){
chrome.tabs.getSelected((tab)=>{
this.tabId = tab.id;
this.captureWebPage();
})
},
//初始化canvas的宽高
initWH(){
this.canvas.width = this.vw;
this.canvas.height = this.vh;
},
//将当前窗口内容转换成 image Data
captureWebPage(){
chrome.tabs.captureVisibleTab((data)=>{
this.screenData = data;
//分阶段绘制canvas
this.drawImage();
})
},
//往Canvas中填充图片
drawImage(){
let img = new Image();
img.src = this.screenData;
img.onload = ()=>{
this.ctx.drawImage(img,this.offsetX,this.offsetY,this.vw,this.vh,0,0,this.vw,this.vh);
this.getImage();
};
},
//获取到最终的图片
getImage(){
this.captureImgData = this.canvas.toDataURL('image/png');
this.callback(this.captureImgData);
}
}
7. manifest.json核心配置:
{
"name": "抓取网页内容、对网页进行多类型截屏",
"description": "",
"version": "1.0",
"permissions": [
"activeTab",
"*://*/*",
"unlimitedStorage",
"storage",
"pageCapture",
"tabs",
"<all_urls>"
],
"background": {
"scripts": ["scripts/background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["*://*.baidu.com/*"],
"js": ["scripts/vue.js","scripts/jquery.js","scripts/content-script.js"],
"css" : ["css/bootstrap.min.css"]
}
],
"browser_action": {
"default_title": "Set this page's color.",
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"manifest_version": 2
}
8. 扩展文件目录:
|— catch_web_page_content
|— css
|— bootstrap.min.css
|— images
|— scripts
|— background.js
|— content-script.js
|— jquery.js
|— popup.js
|— vue.js
|— icon.png
|— manifest.json
|— popup.html
7. github地址: