javascript 如何在 web 应用程序中禁用 iOS 的“摇动以撤消”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6520125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to disable iOS "Shake to Undo" in a webapp
提问by Johan Sahlén
I'm building a game as a webapp for the iPad. It incorporates a shake action to trigger an event for one of the screens, but, since it also has a information collection form, sometimes that shake action triggers the annoying "Shake to Undo" dialog. The form input the user has typed in don't even exist in the DOM anymore when the user reaches the shake action, so in my mind the Undo function shouldn't be triggered, but unfortunately it is. There is no way this can be wrapped in a native wrapper (PhoneGap or other), so I was wondering if anyone knows if it's at all possible to disable this functionality for a specific web page/app, through CSS or JavaScript?
我正在构建一个游戏作为 iPad 的 web 应用程序。它包含一个摇动动作来触发其中一个屏幕的事件,但是,由于它也有一个信息收集表格,有时摇动动作会触发恼人的“摇动以撤消”对话框。当用户到达摇动动作时,用户输入的表单输入甚至不再存在于 DOM 中,所以在我看来不应该触发 Undo 功能,但不幸的是它是。无法将其包装在本机包装器(PhoneGap 或其他)中,所以我想知道是否有人知道是否可以通过 CSS 或 JavaScript 为特定网页/应用程序禁用此功能?
Thanks.
谢谢。
采纳答案by Maxsquatch
I recently ran into this issue while developing a game where a user pairs devices using WebSockets. Unfortunately none of the solutions mentioned above work.
我最近在开发一个用户使用 WebSockets 配对设备的游戏时遇到了这个问题。不幸的是,上面提到的解决方案都没有奏效。
In short, the game involved a user subscribing to a channel via a form on their phone. Once subscribed they would shake the device and a scenario would play out on their desktop. The problem was that any time someone shook an iOS device the "undo typing" alert would pop up.
简而言之,该游戏涉及用户通过手机上的表格订阅频道。订阅后,他们会摇晃设备,然后在他们的桌面上播放一个场景。问题是,只要有人摇晃 iOS 设备,就会弹出“撤消输入”警报。
Here are the only two solutions that I've found for this issue.
这是我为这个问题找到的仅有的两个解决方案。
Prevent your input from ever losing focus. This will require you to prevent form submission if the input is part of a form. You must also listen for "touchstart" instead of "click" on any anchors and prevent the touchstart event from propagating. This will prevent that anchor from gaining focus and your input from losing focus. This approach has some disadvantages for sure.
Add a "keydown" event handler to the window and prevent the event from propagating. This prevents any values from getting inserted into the input on iOS devices. I also had to create an object that mapped the keycodes to the proper character. This is the route I ended going because all I needed in my input was a 6 character code so I only needed numbers. If you need more than just numbers this may be a pain in the ass. On key down, snag that character via the keycode and set the value of the input. This tricks iOS into thinking that no value was ever inserted into the input via the keyboard so there is nothing for it to undo.
防止您的输入永远失去焦点。如果输入是表单的一部分,这将要求您阻止表单提交。您还必须在任何锚点上侦听“touchstart”而不是“click”,并防止传播 touchstart 事件。这将防止该锚获得焦点以及您的输入失去焦点。这种方法肯定有一些缺点。
向窗口添加“keydown”事件处理程序并防止事件传播。这可以防止任何值被插入到 iOS 设备的输入中。我还必须创建一个将键码映射到正确字符的对象。这是我结束的路线,因为我在输入中只需要一个 6 个字符的代码,所以我只需要数字。如果您需要的不仅仅是数字,这可能会很麻烦。在按下键时,通过键码获取该字符并设置输入值。这让 iOS 认为从来没有通过键盘将值插入到输入中,因此没有任何东西可以撤消。
Keep in mind preventing the keydown event from propagating does not prevent input on the stock android browser, so it will just function normally. But that is OK since this is not an android issue. You can prevent duplicate values from getting inserted by listening for the input event on the input itself and removing the keydown listener if this event is received.
请记住,阻止 keydown 事件传播并不会阻止在股票 android 浏览器上的输入,因此它只会正常运行。但这没关系,因为这不是 android 问题。您可以通过侦听输入本身的输入事件并在收到此事件时删除 keydown 侦听器来防止插入重复值。
var codes = {
48: 0,
49: 1,
50: 2,
51: 3,
52: 4,
53: 5,
54: 6,
55: 7,
56: 8,
57: 9
},
myInput = document.getElementById("myInput");
var keydownHelper = function (e) {
e.preventDefault();
myInput.removeEventListener("input", inputHelper);
var val = myInput.value;
// Delete
if (e.keyCode === 8 && val.length) {
myInput.value = val.slice(0, val.length - 1);
return;
}
// If not a number, do nada
if (typeof codes[e.keyCode] === "undefined") { return; }
val += codes[e.keyCode];
myInput.value = val;
};
var inputHelper = function (e) {
e.preventDefault();
window.removeEventListener("keydown", keydownHelper);
};
myInput.addEventListener("input", inputHelper);
window.addEventListener("keydown", keydownHelper);
回答by John Kramlich
This blog describes a very simple shake detection using the DeviceMotionEvent listener:
该博客描述了使用 DeviceMotionEvent 侦听器进行的非常简单的抖动检测:
http://www.jeffreyharrell.com/blog/2010/11/creating-a-shake-event-in-mobile-safari/
http://www.jeffreyharrell.com/blog/2010/11/creating-a-shake-event-in-mobile-safari/
Try the following code to disable to undo event happening:
尝试以下代码以禁用撤消事件发生:
window.addEventListener('devicemotion', function (e) {
// This is where you put your code for dealing with the shake event here
// Stop the default behavior from triggering the undo dialog (hopefully)
e.preventDefault();
});
There is one other thing I can think of which would be to turn the text input into a readonly item after you are done with it. Presumably, a read only input field cannot make use of the undo function, though I haven't tested it. It's odd that the feature fires even after the input is no longer part of the DOM.
我能想到的另一件事是在完成文本输入后将其转换为只读项目。据推测,只读输入字段不能使用撤消功能,尽管我还没有测试过。奇怪的是,即使在输入不再是 DOM 的一部分之后,该功能也会触发。
I'm not sure if preventing a shake action can be done through the -webkit- properties in CSS. Here is a list of webkit specific CSS properties (which may not contain 100% of the properties accessible).
我不确定是否可以通过 CSS 中的 -webkit- 属性来防止摇晃动作。这是 webkit 特定 CSS 属性的列表(可能不包含 100% 的可访问属性)。
回答by Tobias Christian Jensen
For PhoneGap I just inserted this line: [UIApplication sharedApplication].applicationSupportsShakeToEdit = NO; in the webViewDidFinishLoad class and it worked wonders for me.
对于 PhoneGap,我刚刚插入了这一行: [UIApplication sharedApplication].applicationSupportsShakeToEdit = NO; 在 webViewDidFinishLoad 类中,它为我创造了奇迹。
Just go to the MainViewController.m and change webViewDidFinishLoad to look like this:
只需转到 MainViewController.m 并将 webViewDidFinishLoad 更改为如下所示:
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
// Black base color for background matches the native apps
theWebView.backgroundColor = [UIColor blackColor];
[UIApplication sharedApplication].applicationSupportsShakeToEdit = NO;
return [super webViewDidFinishLoad:theWebView];
}
回答by Augustine P A
Objective-C
目标-C
Just add the line of code inside "- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions"
只需在“- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions”中添加一行代码
[application setApplicationSupportsShakeToEdit:NO];
Swift 2.x
斯威夫特 2.x
Add single line of code in appDelegate.swift didFinishLaunchingWithOptionsmethod
在 appDelegate.swift didFinishLaunchingWithOptions方法中添加单行代码
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
application.applicationSupportsShakeToEdit = false
return true
}
Swift 3.x
斯威夫特 3.x
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
application.applicationSupportsShakeToEdit = false
return true
}
回答by Saeed HosseinPoor
First solution
第一个解决方案
The easiest way is to use this plugin:
最简单的方法是使用这个插件:
https://github.com/nleclerc/cordova-plugin-ios-disableshaketoedit
https://github.com/nleclerc/cordova-plugin-ios-disableshaketoedit
Second solution
第二种解决方案
If you don't want to use the above plugin then you should do it manually by opening the MainViewController.m and change webViewDidFinishLoad to look like this:
如果你不想使用上面的插件,那么你应该手动打开 MainViewController.m 并将 webViewDidFinishLoad 更改为如下所示:
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
// Black base color for background matches the native apps
theWebView.backgroundColor = [UIColor blackColor];
[UIApplication sharedApplication].applicationSupportsShakeToEdit = NO;
return [super webViewDidFinishLoad:theWebView];
}
Third solution
第三种解决方案
it's another solution i designed to disable "Shake To Undo" which works on text inputs. note that users are not allowed to insert emojis.
这是我设计的另一个解决方案,用于禁用适用于文本输入的“Shake To Undo”。请注意,不允许用户插入表情符号。
<body>
<textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
<script>
textArea = document.getElementById("textarea");
textArea.onkeypress = function(event){
event.preventDefault();
var nationUnicode=event.which;
var utf8=encodeURIComponent(String.fromCharCode(parseInt(nationUnicode, 10)));
if (utf8.search("%EF") != 0) //value is not an Emoji
textArea.value= textArea.value + String.fromCharCode(nationUnicode);
}
textArea.onkeydown = function (event){
if (event.keyCode == 8){
event.preventDefault();
var txtval = textArea.value;
textArea.value = txtval.slice(0, - 1);
}
}
</script>
</body>
回答by Josh Duck
I found a workaround that works consistently: you can host the text input in a frame. When you're done with the input, remove the frame from the page. This seems to do the trick.
我找到了一种始终有效的解决方法:您可以在框架中托管文本输入。完成输入后,从页面中移除框架。这似乎可以解决问题。
function resetIframe() {
// Remove the old frame
document.body.removeChild(frame);
// Create a new frame that has an input internally
frame = document.createElement('iframe');
frame.src = '/html-with-input.html';
frame.style = 'border: 0; height: 30px; width: 200px;'
document.body.appendChild(frame);
// When the frame is ready, grab a reference to the input
frame.addEventListener('load', () => {
const input = frame.contentDocument.body.querySelector('input');
console.log(frame, frame.contentDocument.body)
// When the input changes, grab the value
input.addEventListener('input', e => {
document.getElementById('output').innerText = e.target.value;
});
});
}
Here's a proof of concept: https://codepen.io/joshduck/full/RJMYRd/
回答by Bob Dowling
See: How to stop the UITextField from responding to the shake gesture?
For phonegap, set this property within the webViewFinishLoad method in AppDelegate.m
对于 phonegap,在 AppDelegate.m 的 webViewFinishLoad 方法中设置此属性
回答by Alex KeySmith
Perhaps try event.preventDefault();
in your DeviceMotionEvent listener ?
也许尝试event.preventDefault();
在您的 DeviceMotionEvent 侦听器中?
Looking around Stack Overflow, I can see other people have had success disabling default "events" using CSS (oddly).
环顾 Stack Overflow,我可以看到其他人已经成功地使用 CSS(奇怪)禁用了默认“事件”。
Prevent default Press but not default Drag in iOS MobileSafari?
回答by Ning
Put the input into an iframe, reload the iframe when you don't need the input.
将输入放入 iframe,不需要输入时重新加载 iframe。