简体   繁体   English

Angular - iPhone / iPad上的ng-blur问题

[英]Angular - issue with ng-blur on iPhone/iPad

I use AngularJS 1.4.7 我使用AngularJS 1.4.7

I have editable input. 我有可编辑的输入。 If we focus on input and after click outside of this input field, script will do function "save()" in ng-blur . 如果我们专注于输入并在此输入字段之外单击后,脚本将在ng-blur执行"save()"功能。 Everything work correctly, but on iPhone 5/6 and iPad don't work (not execute anything in ng-blur ). 一切正常,但在iPhone 5/6iPad上无法正常工作(不能在ng-blur执行任何操作)。 I don't know why, but I deduce that problem is in focus/touch action. 我不知道为什么,但我推断这个问题是focus/touch动作。 Someone know where is the problem? 有人知道问题出在哪里?

Fix ng-blur not working on empty space and most elements with iOS 修复ng-blur无法处理空白空间和大多数iOS元素

Goal 目标

In my app, we wanted to hide open menus or search results when clicking away from the menu or search box. 在我的应用程序中,我们希望在单击菜单或搜索框时隐藏打开的菜单或搜索结果。

Problem 问题

iOS Safari does not blur properly when clicking away from the current element. 单击远离当前元素时,iOS Safari无法正常模糊。

Note 注意

You do not need a special directive. 您不需要特殊指令。 The problem is not with ng-blur, which works fine. 问题不在于ng-blur,它工作正常。 The problem is that a blur event never occurs because of Apple's unusual design on iOS, regardless of whether you use ng-blur or a native DOM blur event. 问题在于,由于Apple在iOS上的不寻常设计,无论是否使用ng-blur或原生DOM模糊事件,都不会发生模糊事件。

Reason for Issue 发行原因

Apple has designed mobile Safari to perform event bubbling differently than desktop browsers do. Apple设计了移动Safari来执行事件冒泡,这与桌面浏览器不同。 According to official Apple docs, if an element that is clicked has no click listener attached to it, then no click event is triggered. 根据官方Apple文档,如果单击的元素没有附加单击侦听器,则不会触发任何单击事件。 Without a click event, focus does not change and no blur event occurs, so the current element does not lose focus even though the user really did click elsewhere on the page. 如果没有单击事件,焦点不会更改并且不会发生模糊事件,因此即使用户确实单击了页面上的其他位置,当前元素也不会失去焦点。

The blur will only happen if the user clicked an element with a click event listener. 只有当用户单击带有单击事件侦听器的元素时,才会出现模糊。 Some elements like hyperlinks and inputs have "built-in" event listeners for click, and so will always register a click, causing blur to work. 某些元素(如超链接和输入)具有用于单击的“内置”事件侦听器,因此将始终注册单击,从而导致模糊工作。

Normally in desktop browsers, the click event is blindly fired whether there is a registered listener or not in the element's DOM hierarchy. 通常在桌面浏览器中,无论元素的DOM层次结构中是否存在已注册的侦听器,都会盲目触发click事件。 That is why ng-blur works as expected in desktop browsers, even on "empty space". 这就是为什么ng-blur在桌面浏览器中按预期工作,即使在“空白空间”也是如此。

Apple says that for iOS Safari they only dispatch the event if they find an element registered to listen for it. Apple表示,对于iOS Safari,只有在找到注册的元素才能收听该事件时,他们才会调度该事件。

Apple Docs - go to Figure 6-4 Apple Docs - 转到图6-4

Apple's documentation makes it sound like they are looking for a registered event listener and handled on the target element, but that is not the case. Apple的文档听起来像是在寻找已注册的事件监听器并在目标元素上处理,但事实并非如此。 I found the answers in the following article, and more importantly, one of the comments to it. 我在下面的文章中找到了答案,更重要的是,它给出了一个评论。

Quirksmode Article on iOS event delegation 关于iOS事件委托的Quirksmode文章

First, observe that placing a listener on the document or body does not cause the click event to be dispatched on iOS Safari, if the target element has no click event listener and handler. 首先,观察如果目标元素没有单击事件侦听器和处理程序,则在iOS上安装侦听器不会导致在事件上调度click事件。 It works in most browsers, but not on iOS. 它适用于大多数浏览器,但不适用于iOS。

It appears that Apple is checking the DOM hierarchy up to the <body> tag before dispatching the click event, but is not checking the <body> tag or above. 在调度click事件之前,Apple似乎正在检查DOM层​​次结构 <body>标记,但是没有检查<body>标记或更高版本。 Therefore, you need a click event listener attached to an element somewhere below the <body> . 因此,您需要一个附加到<body>下面某个元素的click事件侦听器。

Solution/Workaround 解决方案/解决方法

The solution then is very simple. 那么解决方案非常简单。 All you need to do is to wrap all of the page content in a "master" container element just below the <body> element, and put the listener there instead of on the body or the document. 您需要做的就是将所有页面内容包装在<body>元素正下方的“master”容器元素中,并将侦听器放在那里而不是在主体或文档上。 It can even be an empty handler function. 它甚至可以是一个空的处理函数。 Apple is only checking to see if one is registered. Apple仅检查是否已注册。 The reason for wrapping all content is so that no matter where in the page the user clicks, the bubble-up process will eventually reach the master container. 包装所有内容的原因是,无论用户点击的页面在哪里,起泡过程最终都会到达主容器。

If you do that, then ng-blur will work as expected in iOS, because the click event on empty space (an element with no click event listener) will pass the iOS check when it finds the parent container's click event listener and a click event will be dispatched normally, like it would be in any other browser. 如果你这样做,那么ng-blur将在iOS中按预期工作,因为空白空间上的click事件(没有click事件监听器的元素)将在找到父容器的click事件监听器和click事件时通过iOS检查将被正常发送,就像在任何其他浏览器中一样。

Caution 警告

This solution effectively causes iOS Safari to see a click event listener on every DOM element's hierarchy, tricking it into dispatching the click event on every element, just like a normal browser. 此解决方案有效地使iOS Safari在每个DOM元素的层次结构上看到一个单击事件侦听器,诱使它在每个元素上调度click事件,就像普通的浏览器一样。 I do not know if Apple has a performance reason they avoid this in iOS, or if it is just an aesthetic/developer type preference (see example). 我不知道Apple是否有性能原因他们在iOS中避免这种情况,或者它只是美学/开发者类型偏好(参见示例)。 You will be changing the default iOS behavior in your app by using this workaround. 您将使用此变通方法更改应用中的默认iOS行为。

For example, iOS users may accidentally select text on your page that they did not mean too, and which would not normally occur without a click and hold gesture. 例如,iOS用户可能会意外地在您的页面上选择他们并不意味着的文本,并且如果没有单击并按住手势通常不会发生这种情况。

I don't know why that problem occurs. 我不知道为什么会出现这个问题。 but do one thing. 但做一件事。 create one small directive 'fake-blur' . 创建一个小指令'假模糊'。 then call your method in that directive 然后在该指令中调用您的方法

 App.directive('fakeBlur', function(){ return { restrict: 'A', link: function(scope, element, attrs) { element.blur(function(){ // call you function ex: scope.save(); }) } } }); 
 <input type="text" fake-blur/> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM