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

一、背景

接了个小需求,已有网站,做了个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,
      });
    }
  });
});

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

效果

1.gif
1.gif

你可能感兴趣的:(无星的electron之旅(十二)—— 如何像浏览器一样制作右键菜单)