一、背景
接了个小需求,已有网站,做了个electron的壳,需要添加右键菜单
1.复制图片为base64
2.另存为图片
3.复制图片地址
二、首先需要添加右键菜单
1.主线程 background.js添加右键菜单内容
// 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.页面右键要能调用
需要页面右键能够响应
那么我们需要在页面上能够获取到右键的点击事件
// 页面入口,比如vue的main.js
window.addEventListener("contextmenu", (e) => {
e.preventDefault();
// TODO 通知主线程
});
3.通知主线程响应
通过preload
为window对象挂上一个rightMenu
属性用于沟通调用
// preload.js
contextBridge.exposeInMainWorld("rightMenu", {
show: (domId) =>
ipcRenderer.invoke("show-context-menu", {
domId,
}),
});
// 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,方便后续操作
// background.js
ipcMain.handle("show-context-menu", (event, args) => {
const { domId } = args;
clickDomId = domId;
rightMenu.popup({
window: BrowserWindow.getFocusedWindow().webContents,
});
});
展示
4.实现内容
好像有点简单,随便百度了几个方法,就不多说了,直接放代码
// 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
注入代码即可
// 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,
});
}
});
});
通过这段代码,我们可以为不同样式标签添加不同操作,并且不需要修改网页代码,自然像浏览器一样,添加右键菜单