Iwen's blog Iwen's blog
首页
  • 前端文章

    • JavaScript
    • Vue
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 小程序笔记
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • Linux
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
复盘
关于

Iwen

不摸鱼的哥哥
首页
  • 前端文章

    • JavaScript
    • Vue
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 小程序笔记
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • Linux
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
复盘
关于
  • JavaScript文章

  • Vue文章

  • 学习笔记

  • Vue-iView疑难杂症

  • 微前端

  • 原创经验

    • 微服务集群下的前端接口层优化适配
    • 实现右键菜单
      • contextmenu 事件监听
      • 构造菜单
        • 1\. 实现单例
        • 2\. 创建菜单实例
        • 3\. 初始化菜单
      • 显示菜单
      • 隐藏菜单
    • sassdoc了解及实践
    • vue-router报错Uncaught (in promise)及解决方法
    • nodemailer实现构建打包自动推送邮箱
    • tinypng实现本地自动压缩
  • 前端
  • 原创经验
Mr.w
2021-01-08

实现右键菜单

# 实现自定义右键菜单ContextMenu

鼠标右击网页会弹出默认的浏览器菜单,但是很多时候我们需要自定义右键菜单(比如:在线文档编辑器、定制视频播放器等)。今天我们就来快速实现一个自定义右键菜单。

预览:

right-menu

# contextmenu 事件监听

首先,我们需要禁用浏览器弹出默认菜单的行为,通过阻止 contextMenu (opens new window) 事件的默认行为,并同时触发自定义菜单的显示:

document.addEventListener("contextmenu", (e) => {
  e.preventDefault();
  showMenu(e);
});
1
2
3
4

# 构造菜单

# 1. 实现单例

一个页面中菜单应该只有一个实例,所以我们运用单例模式去创建菜单,典型的单例构造器可以实现为:

const ContextMenu = function (options) {
  // 唯一实例
  let instance;

  // 创建实例方法
  function createMenu() {
    // todo
  }

  return {
    // 获取实例的唯一方式
    getInstance: function () {
      if (!instance) {
        instance = createMenu();
      }
      return instance;
    },
  };
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 2. 创建菜单实例

即实现上面的 createMenu 方法。

菜单的具体配置通过 options 传入,options 的结构定义为:

 options: {
  menus: [{
    name: string, // 菜单名称
    onClick: Function // 菜单点击回调
  }]
 }
1
2
3
4
5
6

通过遍历 options.menus 生成菜单列表,并挂载到 body 中,并最终返回菜单的实例:

function createMenu() {
  const ul = document.createElement("ul");
  ul.classList.add("custom-context-menu");
  const { menus } = options;
  if (menus && menus.length > 0) {
    for (let menu of menus) {
      const li = document.createElement("li");
      li.textContent = menu.name;
      li.onclick = menu.onClick;
      ul.appendChild(li);
    }
  }
  const body = document.querySelector("body");
  body.appendChild(ul);
  return ul;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

创建菜单的主要逻辑就完成了。

# 3. 初始化菜单

接下来向 ContextMenu 中传入 options 以初始化单例构造器:

const menuSinglton = ContextMenu({
  menus: [
    {
      name: "custom menu 1",
      onClick: function (e) {
        console.log("menu1 clicked");
      },
    },
    {
      name: "custom menu 2",
      onClick: function (e) {
        console.log("menu2 clicked");
      },
    },
    {
      name: "custom menu 3",
      onClick: function (e) {
        console.log("menu3 clicked");
      },
    },
  ],
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

初始化完成后,便可以通过 menuSinglton.getInstance() 获取菜单实例了。

# 显示菜单

当我们右击页面时,获取到鼠标的坐标,设置菜单为固定定位(position: fixed),并将其左上角位置设置为鼠标坐标,以实现菜单在鼠标点击位置的弹出:

function showMenu(e) {
  const menus = menuSinglton.getInstance();
  menus.style.top = `${e.clientY}px`;
  menus.style.left = `${e.clientX}px`;
  menus.style.display = "block";
}
1
2
3
4
5
6

# 隐藏菜单

最后,当我们点击页面中的其他区域时需要将菜单隐藏:

function hideMenu(e) {
  const menus = menuSinglton.getInstance();
  menus.style.display = "none";
}

document.addEventListener("click", hideMenu);
1
2
3
4
5
6

大功告成!!

本文Demo参考:Codepen Trick by Day (2020-07-05) Custom Context Menus (opens new window)点击预览

微服务集群下的前端接口层优化适配
sassdoc了解及实践

← 微服务集群下的前端接口层优化适配 sassdoc了解及实践→

最近更新
01
flex布局页面自适应滚动条问题
12-28
02
前后端分离开发请求接口跨域如何携带cookie的问题
12-28
03
怎么实现div长宽比固定width-height4比3
12-28
更多文章>
Theme by Vdoing | Copyright © 2017-2022 Iwen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式