前端 ios 系统 contextmenu 事件模拟

1. 前言

前端开发中为实现业务需求,经常会使用contextmenu事件弹出上下文菜单。在 PC 端通常使用右键可以触发contextmenu事件,在 Android 端也可以使用长按触发,但是在 ios 端通过长按却无法触发,即使阻止了默认事件:

js 复制代码
document.addEventListener('contextmenu', (e) => {
    e.preventDefault();
    // 业务逻辑
});

通过查看contextmenu事件的浏览器兼容性,发现 ios 系统不支持contextmenu事件,但是项目中又有这种需求,那该怎么办呢?

2. 解决方案

比较合适的方案是使用TouchEvent模拟长按事件,事件触发之后派发一个contextmenu事件,关键代码如下:

js 复制代码
let timer;
document.addEventListener('touchstart', (e) => {
    timer = setTimeout(fireContextMenuEvent, 750, e); // 750ms之后触发,可根据情况调整
});
document.addEventListener('touchend', (e) => {
    clearTimeout(timer);
});
const fireContextMenuEvent = (e) => { // 参数为原来的 touchstart event
    clearTimeout(timer);
    const event = e.changedTouches[0];
    e.target.dispatchEvent(new MouseEvent( // 手动派发一个名叫 contextmenu 的 MouseEvent
        'contextmenu', { // 传入 contextmenu 所需的参数
            bubbles: true,
            cancelable: true,
            clientX: event.clientX,
            clientY: event.clientY,
            // ... 省略了其他参数
        },
    ));
};

以上只给出了关键代码,实际上使用的时候需要处理一些特殊情况,比如touchstart之后移动了位置就不能再触发contextmenu事件了,具体使用的话可以参考这个代码,这是一个模拟长按的代码,只需要修改一部分内容就能使用。

3. 能力检测

还有个问题是我们不能在所有浏览器上添加这段代码,Android 端等正常的浏览器我们还是希望使用原生的contextmenu事件,所以需要做浏览器能力检测,可以使用如下代码检测浏览器是否支持contextmenu事件:

js 复制代码
'oncontextmenu' in window

本来期望这行代码能够在 ios 中输出false,然而令人大跌眼镜的是该代码输出了true,但是contextmenu事件确实没接收到(有点懵了,到底支不支持啊),猜测可能是 ios 支持该事件,只是无法触发。因此问题转变为了判断 ios 系统:

js 复制代码
const isIOS = /(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent);
if (isIOS) {
    // 执行上述代码
}

4. 长按提示问题

还有个问题是当用户在 ios 系统的浏览器中长按时,系统会自动选中长按的内容,并提示一些操作,我们在长按时不希望出现这个行为,可以在 CSS 中添加如下内容:

css 复制代码
body {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
}

5. 总结

ios 系统浏览器无法触发contextmenu事件,在 ios 中使用contextmenu时可以通过TouchEvent模拟实现想要的效果,在不希望长按出现提示的时候可以通过添加 CSS 去除该行为。

相关推荐
终将老去的穷苦程序员1 小时前
使用 IntelliJ IDEA 创建简单的 Java Web 项目
java·前端·intellij-idea
JINGWHALE12 小时前
设计模式 行为型 模板方法模式(Template Method Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·模板方法模式
&活在当下&3 小时前
Vue3 给 reactive 响应式对象赋值
前端·vue.js
坐公交也用券3 小时前
VUE3配置后端地址,实现前后端分离及开发、正式环境分离
前端·javascript·vue.js
独孤求败Ace4 小时前
第31天:Web开发-PHP应用&TP框架&MVC模型&路由访问&模版渲染&安全写法&版本漏洞
前端·php·mvc
星星不闪包退换4 小时前
css面试常考布局(圣杯布局、双飞翼布局、三栏布局、两栏布局、三角形)
前端·css
疯狂的沙粒5 小时前
HTML和CSS相关的问题,如何避免 CSS 样式冲突?
前端·css·html
家电修理师5 小时前
HBuilderX打包ios保姆式教程
前端·ios
草木红5 小时前
六、Angular 发送请求/ HttpClient 模块
服务器·前端·javascript·angular.js
kkkkatoq5 小时前
EasyExcel的应用
java·前端·servlet