我正在为 iPad 编写一个网络应用程序(不是普通的 App Store 应用程序——它是使用 HTML、CSS 和 JavaScript 编写的)。由于键盘占据了屏幕的很大一部分,因此在显示键盘时更改应用程序的布局以适应剩余空间是有意义的。但是,我发现无法检测何时或是否显示键盘。
我的第一个想法是假设当文本字段具有焦点时键盘是可见的。但是,当将外部键盘连接到 iPad 时,当文本字段获得焦点时,虚拟键盘不会显示。
在我的实验中,键盘也不会影响任何 DOM 元素的高度或滚动高度,并且我没有发现表明键盘是否可见的专有事件或属性。
我找到了一个可行的解决方案,虽然它有点难看。它也不会在所有情况下都有效,但它对我有用。由于我正在调整用户界面的大小以适应 iPad 的窗口大小,因此用户通常无法滚动。换句话说,如果我设置窗口的 scrollTop,它将保持为 0。
另一方面,如果显示键盘,则滚动突然起作用。所以我可以设置scrollTop,立即测试它的值,然后重置它。这是使用 jQuery 在代码中的样子:
$(document).ready(function(){
$('input').bind('focus',function() {
$(window).scrollTop(10);
var keyboard_shown = $(window).scrollTop() > 0;
$(window).scrollTop(0);
$('#test').append(keyboard_shown?'keyboard ':'nokeyboard ');
});
});
通常,您希望这对用户不可见。不幸的是,至少在模拟器中运行时,iPad 明显(虽然很快)再次上下滚动。尽管如此,它仍然有效,至少在某些特定情况下如此。
我已经在 iPad 上进行了测试,它似乎工作正常。
您可以使用 focusout 事件来检测键盘解除。这就像模糊,但气泡。它会在键盘关闭时触发(当然,在其他情况下也会触发)。在 Safari 和 Chrome 中,只能使用 addEventListener 注册事件,而不能使用传统方法。这是我用来在键盘关闭后恢复 Phonegap 应用程序的示例。
document.addEventListener('focusout', function(e) {window.scrollTo(0, 0)});
如果没有此代码段,应用程序容器会一直停留在向上滚动的位置,直到页面刷新。
focusout
是在由于任何原因失去焦点时触发的。因此,它无助于确定虚拟键盘是否曾经打开过,或者是否使用了外部键盘并且该字段具有焦点而没有使用虚拟键盘。
如果有屏幕键盘,聚焦视口底部附近的文本字段将导致 Safari 将文本字段滚动到视图中。可能有一些方法可以利用这种现象来检测键盘的存在(在页面底部有一个很小的文本字段,可以暂时获得焦点,或者类似的东西)。
也许更好的解决方案是在各种输入字段上绑定(在我的情况下使用 jQuery)“模糊”事件。
这是因为当键盘消失时,所有表单字段都变得模糊。所以对于我的情况,这个剪断解决了这个问题。
$('input, textarea').bind('blur', function(e) {
// Keyboard disappeared
window.scrollTo(0, 1);
});
希望能帮助到你。米歇尔
编辑:由 Apple 记录,虽然我实际上无法让它工作:WKWebView Behavior with Keyboard Displays:“在 iOS 10 中,WKWebView 对象通过在显示键盘时更新它们的 window.innerHeight 属性来匹配 Safari 的本机行为,并且不调用调整大小事件”(也许可以使用焦点或焦点加延迟来检测键盘而不是使用调整大小)。
编辑:代码假定屏幕键盘,而不是外部键盘。离开它是因为信息可能对只关心屏幕键盘的其他人有用。使用 http://jsbin.com/AbimiQup/4 查看页面参数。
我们测试 document.activeElement
是否是显示键盘的元素(输入类型=文本、文本区域等)。
以下代码为我们的目的捏造了一些东西(尽管通常不正确)。
function getViewport() {
if (window.visualViewport && /Android/.test(navigator.userAgent)) {
// https://developers.google.com/web/updates/2017/09/visual-viewport-api Note on desktop Chrome the viewport subtracts scrollbar widths so is not same as window.innerWidth/innerHeight
return {
left: visualViewport.pageLeft,
top: visualViewport.pageTop,
width: visualViewport.width,
height: visualViewport.height
};
}
var viewport = {
left: window.pageXOffset, // http://www.quirksmode.org/mobile/tableViewport.html
top: window.pageYOffset,
width: window.innerWidth || documentElement.clientWidth,
height: window.innerHeight || documentElement.clientHeight
};
if (/iPod|iPhone|iPad/.test(navigator.platform) && isInput(document.activeElement)) { // iOS *lies* about viewport size when keyboard is visible. See http://stackoverflow.com/questions/2593139/ipad-web-app-detect-virtual-keyboard-using-javascript-in-safari Input focus/blur can indicate, also scrollTop:
return {
left: viewport.left,
top: viewport.top,
width: viewport.width,
height: viewport.height * (viewport.height > viewport.width ? 0.66 : 0.45) // Fudge factor to allow for keyboard on iPad
};
}
return viewport;
}
function isInput(el) {
var tagName = el && el.tagName && el.tagName.toLowerCase();
return (tagName == 'input' && el.type != 'button' && el.type != 'radio' && el.type != 'checkbox') || (tagName == 'textarea');
};
上面的代码只是大概的:分体键盘、非对接键盘、物理键盘是错误的。根据顶部的评论,您可以使用 window.innerHeight
属性在 Safari(自 iOS8 起?)或 WKWebView(自 iOS10 起)上的给定代码做得更好。
我在其他情况下发现了失败:例如,将焦点放在输入上,然后转到主屏幕,然后返回页面; iPad 不应该让视口变小;旧的 IE 浏览器无法运行,Opera 无法运行,因为 Opera 在键盘关闭后一直专注于元素。
但是,如果视口可缩放(或在首选项中启用强制缩放),标记的答案(更改滚动顶部以测量高度)具有令人讨厌的 UI 副作用。我不使用其他建议的解决方案(更改滚动顶部),因为在 iOS 上,当视口可缩放并滚动到焦点输入时,滚动和缩放和焦点之间存在错误的交互(这可能会在视口之外留下刚刚聚焦的输入 - 不是可见的)。
在焦点事件期间,您可以滚动超过文档高度,并且 window.innerHeight 会神奇地减少虚拟键盘的高度。请注意,横向和纵向的虚拟键盘大小不同,因此您需要在它发生变化时重新检测它。我建议不要记住这些值,因为用户可以随时连接/断开蓝牙键盘。
var element = document.getElementById("element"); // the input field
var focused = false;
var virtualKeyboardHeight = function () {
var sx = document.body.scrollLeft, sy = document.body.scrollTop;
var naturalHeight = window.innerHeight;
window.scrollTo(sx, document.body.scrollHeight);
var keyboardHeight = naturalHeight - window.innerHeight;
window.scrollTo(sx, sy);
return keyboardHeight;
};
element.onfocus = function () {
focused = true;
setTimeout(function() {
element.value = "keyboardHeight = " + virtualKeyboardHeight()
}, 1); // to allow for orientation scrolling
};
window.onresize = function () {
if (focused) {
element.value = "keyboardHeight = " + virtualKeyboardHeight();
}
};
element.onblur = function () {
focused = false;
};
请注意,当用户使用蓝牙键盘时,keyboardHeight 为 44,即 [previous][next] 工具栏的高度。
进行此检测时会有一点点闪烁,但似乎无法避免。
仅在 Android 4.1.1 上测试:
模糊事件不是测试键盘上下的可靠事件,因为用户可以选择显式隐藏键盘,这不会触发导致键盘显示的字段上的模糊事件。
但是,如果键盘因任何原因向上或向下,resize 事件就像一个魅力。
咖啡:
$(window).bind "resize", (event) -> alert "resize"
无论出于何种原因显示或隐藏键盘时都会触发。
但是请注意,在 android 浏览器(而不是应用程序)的情况下,有一个可伸缩的 url 栏,当它被收回时不会触发调整大小,但会改变可用的窗口大小。
不要检测键盘,而是尝试检测窗口的大小
如果窗口的高度减小了,宽度仍然不变,则表示键盘已打开。否则键盘关闭,您还可以添加,测试任何输入字段是否处于焦点。
例如,试试这个代码。
var last_h = $(window).height(); // store the intial height.
var last_w = $(window).width(); // store the intial width.
var keyboard_is_on = false;
$(window).resize(function () {
if ($("input").is(":focus")) {
keyboard_is_on =
((last_w == $(window).width()) && (last_h > $(window).height()));
}
});
visual viewport API 用于对虚拟键盘更改和视口可见性做出反应。
Visual Viewport API 提供了一种明确的机制来查询和修改窗口的可视视口的属性。视觉视口是屏幕的视觉部分,不包括屏幕键盘、捏拉缩放区域之外的区域或任何其他不随页面尺寸缩放的屏幕工件。
function viewportHandler() {
var viewport = event.target;
console.log('viewport.height', viewport.height)
}
window.visualViewport.addEventListener('scroll', viewportHandler);
window.visualViewport.addEventListener('resize', viewportHandler);
window.visualViewport
(如果存在)在 Android 和 iOS 上的浏览器 chrome 隐藏/显示以及屏幕键盘显示/隐藏时触发 resize
事件。它也会在其他事件发生时触发,例如浏览器调整大小和捏缩放。另一个不错的选择是 web.dev/virtualkeyboard,但它仅适用于 Android/Chrome。
试试这个:
var lastfoucsin;
$('.txtclassname').click(function(e)
{
lastfoucsin=$(this);
//the virtual keyboard appears automatically
//Do your stuff;
});
//to check ipad virtual keyboard appearance.
//First check last focus class and close the virtual keyboard.In second click it closes the wrapper & lable
$(".wrapperclass").click(function(e)
{
if(lastfoucsin.hasClass('txtclassname'))
{
lastfoucsin=$(this);//to avoid error
return;
}
//Do your stuff
$(this).css('display','none');
});`enter code here`
这个想法是将固定的 div 添加到底部。当显示/隐藏虚拟键盘时发生滚动事件。另外,我们找出键盘高度
const keyboardAnchor = document.createElement('div') keyboardAnchor.style.position = 'fixed' keyboardAnchor.style.bottom = 0 keyboardAnchor.style.height = '1px' document.body.append(keyboardAnchor) window.addEventListener('scroll ', ev => { console.log('键盘高度', window.innerHeight - keyboardAnchor.getBoundingClientRect().bottom) }, true)
此解决方案记住滚动位置
var currentscroll = 0;
$('input').bind('focus',function() {
currentscroll = $(window).scrollTop();
});
$('input').bind('blur',function() {
if(currentscroll != $(window).scrollTop()){
$(window).scrollTop(currentscroll);
}
});
问题是,即使在 2014 年,设备在软键盘打开时也不一致地处理屏幕调整大小事件和滚动事件。
我发现,即使你使用的是蓝牙键盘,iOS 也会特别触发一些奇怪的布局错误;因此,我不必检测软键盘,而只需要针对非常窄且具有触摸屏的设备。
我使用媒体查询(或 window.matchMedia)进行宽度检测,使用 Modernizr 进行触摸事件检测。
如前一个答案中所述,当键盘出现时,window.innerHeight 变量现在在 iOS10 上得到正确更新,因为我不需要支持早期版本,所以我想出了以下技巧,这可能比讨论的要容易一些“解决方案”。
//keep track of the "expected" height
var windowExpectedSize = window.innerHeight;
//update expected height on orientation change
window.addEventListener('orientationchange', function(){
//in case the virtual keyboard is open we close it first by removing focus from the input elements to get the proper "expected" size
if (window.innerHeight != windowExpectedSize){
$("input").blur();
$("div[contentEditable]").blur(); //you might need to add more editables here or you can focus something else and blur it to be sure
setTimeout(function(){
windowExpectedSize = window.innerHeight;
},100);
}else{
windowExpectedSize = window.innerHeight;
}
});
//and update the "expected" height on screen resize - funny thing is that this is still not triggered on iOS when the keyboard appears
window.addEventListener('resize', function(){
$("input").blur(); //as before you can add more blurs here or focus-blur something
windowExpectedSize = window.innerHeight;
});
那么你可以使用:
if (window.innerHeight != windowExpectedSize){ ... }
检查键盘是否可见。我已经在我的网络应用程序中使用它一段时间了,它运行良好,但是(与所有其他解决方案一样)你可能会发现它失败的情况是因为“预期”大小没有正确更新或其他原因。
也许在您的应用程序设置中有一个复选框更容易,用户可以在其中切换“已连接外部键盘?”。
用小字体向用户说明当前浏览器无法检测到外部键盘。
我进行了一些搜索,但找不到“在键盘上显示”或“在键盘上被解雇”的任何具体内容。请参阅the official list of supported events。另请参阅 iPad 的 Technical Note TN2262。您可能已经知道,您可以连接一个身体事件 onorientationchange
来检测横向/纵向。
同样,但一个疯狂的猜测......你有没有尝试检测调整大小?视口更改可能会从显示/隐藏的键盘间接触发该事件。
window.addEventListener('resize', function() { alert(window.innerHeight); });
这只会在任何调整大小事件时提醒新高度......
我自己没有尝试过,所以这只是一个想法……但是您是否尝试过使用带有 CSS 的媒体查询来查看窗口高度何时发生变化,然后为此更改设计?我想 Safari 移动版没有将键盘识别为窗口的一部分,因此希望可以正常工作。
例子:
@media all and (height: 200px){
#content {height: 100px; overflow: hidden;}
}
好吧,您可以检测输入框何时获得焦点,并且您知道键盘的高度。还有可用的 CSS 来获取屏幕的方向,所以我认为你可以破解它。
不过,您可能希望以某种方式处理物理键盘的情况。
不定期副业成功案例分享
.scrollTop(1)
不会同样有效并且不那么明显吗?