我的GitHub
0%

无星的electron之旅(十二)—— 如何像浏览器一样制作右键菜单

一、背景

接了个小需求,已有网站,做了个electron的壳,需要添加右键菜单
1.复制图片为base64
2.另存为图片
3.复制图片地址

二、首先需要添加右键菜单

1.主线程 background.js添加右键菜单内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// background.js
///////////
const rightMenu = initRightMenu();
function initRightMenu() {
const rightTemplate = [
{
label: "复制图片为base64",
click: () => {
console.log("复制图片为base64");
},
},
{
label: "另存为图片",
click: () => {
console.log("另存为图片");
},
},
{
label: "复制图片URL",
click: () => {
console.log("复制图片URL");
},
},
];
const menu = Menu.buildFromTemplate(rightTemplate);
return menu;
}
///////////

2.页面右键要能调用

需要页面右键能够响应

那么我们需要在页面上能够获取到右键的点击事件

1
2
3
4
5
// 页面入口,比如vue的main.js
window.addEventListener("contextmenu", (e) => {
e.preventDefault();
// TODO 通知主线程
});

3.通知主线程响应

通过preload为window对象挂上一个rightMenu属性用于沟通调用

1
2
3
4
5
6
7
8
// preload.js
contextBridge.exposeInMainWorld("rightMenu", {
show: (domId) =>
ipcRenderer.invoke("show-context-menu", {
domId,
}),
});

1
2
3
4
5
6
7
8
9
10
11
12
// main.js
window.addEventListener("contextmenu", (e) => {
e.preventDefault();
const domName = e.target.localName;
if (domName === "img") {
if (e.target.id === "") {
const date = new Date().valueOf();
e.target.id = date;
}
window.rightMenu.show(e.target.id);
}
});

因为我们的目标是图片,所以判断一下,是图片才调用右键展示

同时我们需要知道我们需要操作哪个dom,所以为其设置一个id,方便后续操作

1
2
3
4
5
6
7
8
// background.js
ipcMain.handle("show-context-menu", (event, args) => {
const { domId } = args;
clickDomId = domId;
rightMenu.popup({
window: BrowserWindow.getFocusedWindow().webContents,
});
});

展示

4.实现内容

好像有点简单,随便百度了几个方法,就不多说了,直接放代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// preload.js
ipcRenderer.on("base64", (event, args) => {
const { domId } = args;
const element = document.getElementById(domId);
imageToBase64(element.currentSrc);
});

ipcRenderer.on("saveImage", (event, args) => {
const { domId } = args;
const element = document.getElementById(domId);
const nameArray = element.currentSrc.split("/");
const tmpArray = nameArray[nameArray.length - 1].split(".");
const name = tmpArray[0];
// console.log(nameArray);
download(element.currentSrc, name);
});

ipcRenderer.on("copyUrl", (event, args) => {
const { domId } = args;
const element = document.getElementById(domId);
copy(element.currentSrc);
});

// base64
const getBase64Image = (img) => {
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
let ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
if (ext === "jpg") {
ext = "jpeg"; //这个地方是由于如果是jpg, 他会识别成image/png
}
const dataURL = canvas.toDataURL("image/" + ext);
return dataURL;
};

const imageToBase64 = (url) => {
let image = new Image();
image.crossOrigin = "";
image.src = url;
image.onload = function () {
const base64 = getBase64Image(image);
// console.log(base64);
copy(base64);
};
};

const download = (data, name) => {
if (!data) {
return;
}
getUrlBase64(data).then((base64) => {
let a = document.createElement("a");
a.style.display = "none";
a.download = name;
a.href = base64;
document.body.appendChild(a);
a.click();
});
};
const getUrlBase64 = (url) => {
return new Promise((resolve) => {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let img = new Image();
img.crossOrigin = "Anonymous"; //允许跨域
img.src = url;
img.onload = function () {
canvas.height = 300;
canvas.width = 300;
ctx.drawImage(img, 0, 0, 300, 300);
let dataURL = canvas.toDataURL("image/png");
canvas = null;
resolve(dataURL);
};
});
};

那么如果是加载别人远程页面,没有页面代码,比如我们是个浏览器,如何实现这个功能?

其实也有方法,我们可以通过注入的方式去做

可见无星的electron之旅(九)—— JS注入

在页面加载完成以后,通过preload注入代码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// preload.js
document.addEventListener("DOMContentLoaded", () => {
// 页面内容加载之后需要引入的一些操作
window.addEventListener("contextmenu", (e) => {
e.preventDefault();
const domName = e.target.localName;
if (domName === "img") {
if (e.target.id === "") {
const date = new Date().valueOf();
e.target.id = date;
}
// window.rightMenu.show(e.target.id);
ipcRenderer.invoke("show-context-menu", {
domId: e.target.id,
});
}
});
});

通过这段代码,我们可以为不同样式标签添加不同操作,并且不需要修改网页代码,自然像浏览器一样,添加右键菜单

效果

1