Mikasa

Mikasa 查看完整档案

深圳编辑桂林电子科技大学  |  微电子制造工程 编辑  |  填写所在公司/组织填写个人主网站
编辑

麻烦圈重点

个人动态

Mikasa 赞了文章 · 2月21日

前端小技巧:实现自定义右键菜单(Context Menu)

logo

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

预览:

demo

contextmenu 事件监听

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

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

构造菜单

1. 实现单例

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

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

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

  return {
    // 获取实例的唯一方式
    getInstance: function () {
      if (!instance) {
        instance = createMenu();
      }
      return instance;
    },
  };
};

2. 创建菜单实例

即实现上面的 createMenu 方法。

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

 options: {
  menus: [{
    name: string, // 菜单名称
    onClick: Function // 菜单点击回调
  }]
 }

通过遍历 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;
}

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

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");
      },
    },
  ],
});

初始化完成后,便可以通过 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";
}

隐藏菜单

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

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

document.addEventListener("click", hideMenu);

大功告成!!

本文Demo参考:Codepen Trick by Day (2020-07-05) Custom Context Menus

每天一个小技巧,量变引起质变,希望你和我一起每天多学一点,让技术有趣一点。

所有示例将会汇总到我的 tricks-by-day github项目中,欢迎大家莅临指导 😊

查看原文

赞 14 收藏 12 评论 0

Mikasa 回答了问题 · 2019-09-02

elementUI复选框怎么实现单选?

          <el-table-column
            label="选择"
            align="center">
            <template slot-scope="scope">
               <el-radio v-model="dataId" :label="scope.row.dataId">&thinsp;</el-radio>
            </template>
          </el-table-column>

关注 2 回答 2

Mikasa 回答了问题 · 2019-08-14

el-checkbox-group点击一个checkbox全选,绑定的值也是数组,这是啥问题

el-checkbox选中状态的值为label属性,所以修改为
     <el-checkbox
         v-for="i in item.authDtoList"
         :key="i.id"
         :label="i.id"
     >{{i.authName}}{{i.id}}</el-checkbox>

关注 4 回答 3

Mikasa 回答了问题 · 2019-08-12

解决flex布局时子元素的问题

display:flex下的子元素的flex属性默认设置为flex:0 0 auto,若是不想改变子元素的宽高的话需要设置一下子元素的样式

关注 3 回答 2

Mikasa 回答了问题 · 2019-08-12

解决vue实现搜索后t查询结果的分页显示,点击下一页时不能记住所查询的数据

this.getList方法中应该是没有把请求参数key: this.input实时传入

关注 4 回答 3

Mikasa 赞了回答 · 2019-08-08

解决el input遍历为什么会触发多次blur回调方法,blur不是只有失去焦点时才触发吗

请把唯一值赋给 key ,大概率是 你的 :key="1"的问题,这个要比:key="index"还要严重,强制让 vue 框架认为循环内部是一个组件。

还有,因为 @blur 不是原生方法,可以在 blurInput中加入唯一值,然后再方法中判断唯一值来进行操作。如 blurInput(item.id || 唯一值)

blurInput(id) {
    // 根据唯一值进行操作不同的操作
}

当然,也可以使用事件委托来执行,但是这个需要操作dom节点,且与 vue 事件绑定机制相违背。如果不是考虑数据量极大的情况下,无需采用这种方式。

请看博客:
VUE中演示v-for为什么要加key
利用 WeakMap 对 Vue 新建数组中的对象赋予 :key

有用请采纳,谢谢

关注 2 回答 1

Mikasa 回答了问题 · 2019-08-07

关于父元素子元素定位层级的问题

z-index值只决定同一父元素中的同级子元素的堆叠顺序,需要把你要发生层叠的元素放在同一个父元素下面即可

关注 3 回答 3

Mikasa 回答了问题 · 2019-08-07

解决vue如何识别换行\n?

<div class="desc" v-if="item.payload.ext.type == 'txt'" v-html="item.payload.ext.content|enter"></div>

关注 3 回答 3

Mikasa 回答了问题 · 2019-06-20

element中el-option的禁选逻辑

监听select的v-model数据select,给release选项添加disabled变量属性。变化的时候动态改变disabledStatus的值就可以
<el-option label="release" value="release" :disabled="disabledStatus"></el-option>

关注 2 回答 2

Mikasa 回答了问题 · 2019-04-29

element ui+vue 关于v-model数据绑定的问题

思路换一下可能会好一点,定义一个长度为所有下拉框个数的数组,v-for循环生成下拉框,绑定的值为数组各元素对应的value即可,这样到时候提交之后也很方便获取的,希望对您有帮助

关注 4 回答 3

认证与成就

  • 获得 51 次点赞
  • 获得 6 枚徽章 获得 1 枚金徽章, 获得 1 枚银徽章, 获得 4 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-08-11
个人主页被 899 人浏览