繁体   English   中英

iPad Web 应用程序:使用 JavaScript 在 Z50DE9BC68C93DC32D8C7C905976 中检测虚拟键盘

[英]iPad Web App: Detect Virtual Keyboard Using JavaScript in Safari?

I'm writing a web app for the iPad ( not a regular App Store app - it's written using HTML, CSS and 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)});

如果没有此代码段,应用程序容器将停留在向上滚动位置,直到页面刷新。

如果有屏幕键盘,聚焦靠近视口底部的文本字段将导致 Safari 将文本字段滚动到视图中。 可能有一些方法可以利用这种现象来检测键盘的存在(页面底部有一个微小的文本字段,可以暂时获得焦点,或者类似的东西)。

也许更好的解决方案是在各种输入字段上绑定(在我的情况下使用 jQuery)“模糊”事件。

这是因为当键盘消失时,所有表单域都变得模糊了。 所以对于我的情况,这个剪辑解决了这个问题。

$('input, textarea').bind('blur', function(e) {

       // Keyboard disappeared
       window.scrollTo(0, 1);

});

希望能帮助到你。 米歇尔

在焦点事件期间,您可以滚动超过文档高度,并且 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] 工具栏的高度。

进行此检测时会出现一点点闪烁,但似乎无法避免。

编辑: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 上,当视口可缩放并滚动到焦点输入时,滚动和缩放和焦点之间存在错误的交互(这可能会在视口之外留下一个刚刚聚焦的输入 - 不是可见的)。

仅在 Android 4.1.1 上测试:

模糊事件不是一个可靠的向上和向下测试键盘的事件,因为用户可以选择显式隐藏键盘,这不会在导致键盘显示的字段上触发模糊事件。

但是,如果键盘因任何原因向上或向下移动,则调整大小事件就像一个魅力。

咖啡:

$(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()));
    }   
});     

这是我创建的一个小型库,您可以使用它来制作 Just Works(TM) 的视口

https://github.com/adamjgrant/a-viewport-that-works

试试这个:

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('keyboard height', 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){ ... }

检查键盘是否可见。 我已经在我的网络应用程序中使用它一段时间了,它运行良好,但是(与所有其他解决方案一样)您可能会发现它失败的情况,因为“预期”大小未正确更新或其他原因。

也许在您的应用程序设置中设置一个复选框更容易,用户可以在其中切换“附加外部键盘?”。

以小字体向用户解释当前无法在当今的浏览器中检测到外部键盘。

视觉视口 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);

我自己没有尝试过,所以这只是一个想法……但是您是否尝试过使用带有 CSS 的媒体查询来查看窗口的高度何时发生变化,然后为此更改设计? 我会想象 Safari 移动版不会将键盘识别为窗口的一部分,因此希望能够正常工作。

例子:

@media all and (height: 200px){
    #content {height: 100px; overflow: hidden;}
}

我进行了一些搜索,但找不到“显示键盘上”或“键盘上已关闭”的任何具体内容。 查看支持事件的官方列表 另请参阅 iPad 技术说明 TN2262 您可能已经知道,您可以连接一个onorientationchange身体事件来检测风景/肖像。

同样,但一个疯狂的猜测......你有没有试过检测调整大小? 视口更改可能会从显示/隐藏的键盘间接触发该事件。

window.addEventListener('resize', function() { alert(window.innerHeight); });

这只会在任何调整大小事件时提醒新的高度....

好吧,您可以检测输入框何时获得焦点,并且您知道键盘的高度。 还有可用的 CSS 来获取屏幕的方向,所以我认为你可以破解它。

不过,您可能希望以某种方式处理物理键盘的情况。

暂无
暂无

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

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