Angular9结合fabricjs、hammerjs单击生成IText无法唤起iOS键盘如何解决
根因说明
iOS 端 WebView 有安全策略限制:仅允许在用户主动触发的原生交互事件(touchstart/click等)的同步执行栈内调用输入元素的focus()方法唤起键盘,所有异步执行(包括setTimeout、事件封装库的延迟回调)的focus()调用都会被系统拦截。
你遇到的问题核心是Hammer.js的tap事件为了区分单击/双击、防误触,默认有300ms左右的触发延迟,回调执行时已经脱离了用户交互的同步上下文,所以你的focus逻辑全部被iOS拦截了。
可行解决方案
方案1:替换Hammer.js的tap事件为原生触摸事件判断(最稳定)
自己监听原生touchstart+touchend事件模拟单击逻辑,在原生事件的同步回调内执行IText创建和焦点唤起逻辑:
// Angular组件内的监听逻辑 let touchStartTime = 0; let touchStartX = 0; let touchStartY = 0; const canvasEl = document.getElementById('你的canvas容器ID'); canvasEl.addEventListener('touchstart', (e) => { touchStartTime = Date.now(); touchStartX = e.touches[0].clientX; touchStartY = e.touches[0].clientY; }); canvasEl.addEventListener('touchend', (e) => { // 符合单击判定:触摸时长<300ms,位移<10px if (Date.now() - touchStartTime < 300 && Math.abs(e.changedTouches[0].clientX - touchStartX) < 10 && Math.abs(e.changedTouches[0].clientY - touchStartY) < 10) { // 阻止默认行为避免双击缩放 e.preventDefault(); // 同步创建IText const text = new fabric.IText('输入文本', { left: 100, top: 100, fontSize: 24 }); canvas.add(text); canvas.setActiveObject(text); // 同步唤起编辑,不需要加setTimeout text.enterEditing(); text.hiddenTextarea.focus(); } });
方案2:调整Hammer.js配置消除tap延迟(如果必须用Hammer的tap)
禁用Hammer的doubletap识别器,消除tap事件的触发延迟,确保回调在同步上下文执行:
const hammer = new Hammer(canvasEl); // 先禁用doubletap识别器,避免tap事件等待双击判定 hammer.get('doubletap').set({ enable: false }); // 把tap的识别阈值降到最低 hammer.get('tap').set({ threshold: 10, time: 250 }); hammer.on('tap', (e) => { // 这里的回调现在会同步触发,直接执行IText创建和focus逻辑即可 const text = new fabric.IText('输入文本', { left: e.center.x, top: e.center.y, fontSize: 24 }); canvas.add(text); canvas.setActiveObject(text); text.enterEditing(); text.hiddenTextarea.focus(); });
补充适配点
如果以上方案还是不生效,可以加一个前置兼容处理:在页面初始化时提前插入一个永久透明的textarea,在用户交互的最开始先focus这个提前存在的textarea,再转移焦点到fabric的hiddenTextarea:
/* 全局样式 */ .pre-textarea { position: fixed; opacity: 0; left: -100px; top: -100px; z-index: -1; }
// 在交互回调的最开头同步执行 document.querySelector<HTMLTextAreaElement>('.pre-textarea').focus(); // 再执行fabric的focus逻辑 text.hiddenTextarea.focus();
内容的提问来源于stack exchange,提问作者Jivan
相关产品推荐
相关产品推荐

