Javascript 检测触摸屏设备上虚拟键盘的打开或关闭
对于这个问题,我有一个不雅观的解决方案,我希望其他人可能已经有了更强有力的解决方案Javascript 检测触摸屏设备上虚拟键盘的打开或关闭,javascript,android,ios,keyboard,event-handling,Javascript,Android,Ios,Keyboard,Event Handling,对于这个问题,我有一个不雅观的解决方案,我希望其他人可能已经有了更强有力的解决方案 在触摸屏上,点击可编辑文本字段将打开屏幕键盘,这将改变可用屏幕空间的大小。如果不进行处理,这可能会隐藏关键元素,或将页脚推离适当位置 在笔记本电脑或台式电脑上,打开可编辑文本字段不会导致此类布局更改 在我当前的项目中,我希望确保某些关键项即使在虚拟键盘打开时也可见,因此我需要检测何时发生此类更改。然后,我可以向body元素添加一个类,以更改布局以适应键盘的存在 在线搜索现有解决方案时,我发现: 没有完美的方法可
在触摸屏上,点击可编辑文本字段将打开屏幕键盘,这将改变可用屏幕空间的大小。如果不进行处理,这可能会隐藏关键元素,或将页脚推离适当位置 在笔记本电脑或台式电脑上,打开可编辑文本字段不会导致此类布局更改 在我当前的项目中,我希望确保某些关键项即使在虚拟键盘打开时也可见,因此我需要检测何时发生此类更改。然后,我可以向
body
元素添加一个类,以更改布局以适应键盘的存在
在线搜索现有解决方案时,我发现:
contentEditable
元素将打开屏幕键盘我已经创建了一个。
你可以测试我的解决方案 在我的测试中,如果用户使用带有触摸屏、键盘和鼠标的计算机,并首先使用鼠标(取消)选择可编辑元素,然后立即更改窗口高度,则可能会给出假阳性。如果您在电脑或移动设备上发现其他误报或漏报,请告诉我
;(功能(){
类键盘{
构造函数(){
this.screenWidth=screen.width//检测方向
this.windowHeight=window.innerHeight//检测键盘更改
此参数为0.listeners={
调整大小:[]
,键盘更改:[]
,focuschange:[]
}
document.documentElement中的this.isTouchScreen='ontouchstart'
this.focusElement=null
this.changeFocusTime=new Date().getTime()
此.focusDelay=1000//至少需要600毫秒
让focuschange=this.focuschange.bind(this)
文档.添加的事件列表器(“焦点”,焦点更改,真)
文档。添加了文本列表(“模糊”,焦点更改,真)
window.onresize=this.resizeWindow.bind(this)
}
焦点变更(事件){
让target=event.target
让elementType=null
设checkType=false
设checkEnabled=false
设checkEditable=true
如果(event.type==“焦点”){
elementType=target.nodeName
this.focusElement=目标
开关(元件类型){
案例“输入”:
checkType=true
案例“TEXTAREA”:
checkEditable=false
checkEnabled=true
打破
}
如果(检查类型){
让type=target.type
开关(类型){
案例“颜色”:
案例“复选框”:
案例“无线电”:
案件“日期”:
案例“档案”:
案例“月份”:
案例“时间”:
this.focusElement=null
checkEnabled=false
违约:
elementType+=“[type=“+type+”]”
}
}
如果(选中已启用){
if(target.disabled){
elementType+=(已禁用)
this.focusElement=null
}
}
如果(选中可编辑){
如果(!target.contentEditable){
elementType=null
this.focusElement=null
}
}
}否则{
this.focusElement=null
}
this.changeFocusTime=new Date().getTime()
this.listeners.focuschange.forEach(listener=>{
侦听器(this.focusElement,elementType)
})
}
调整窗口大小(){
设screenWidth=screen.width;
设windowHeight=window.innerHeight
设维数={
宽度:内部宽度
,高度:窗高
}
让方向=(屏幕宽度>屏幕高度)
?“景观”
:“肖像”
让focussion=new Date().getTime()-this.changeFocusTime
让关闭=!this.focusElement
&&(焦点windowHeight)
if((this.screenWidth==screenWidth)&&this.isTouchScreen){
//方向不变
//仅当高度已更改时,“打开”或“关闭”才为真。
//
//边缘案例
//*将给出键盘更改的假阳性。
//*用户拥有一台同时具有屏幕和屏幕的平板电脑
//键盘,并刚刚点击进入或退出
//可编辑区域,还更改了中的窗口高度
//正确的方向,全部用鼠标。
如果(打开){
此。键盘更改(“显示”,尺寸)
}否则,如果(关闭){
此。键盘更改(“隐藏”,尺寸)
}否则{
//假设这是一台带有
//可调整大小的窗口
此选项。调整大小(尺寸、方向)
}
}否则{
//方向改变了
此选项。调整大小(尺寸、方向)
}
this.windowHeight=windowHeight
this.screenWidth=屏幕宽度
}
;(function (){
class Keyboard {
constructor () {
this.screenWidth = screen.width // detect orientation
this.windowHeight = window.innerHeight // detect keyboard change
this.listeners = {
resize: []
, keyboardchange: []
, focuschange: []
}
this.isTouchScreen = 'ontouchstart' in document.documentElement
this.focusElement = null
this.changeFocusTime = new Date().getTime()
this.focusDelay = 1000 // at least 600 ms is required
let focuschange = this.focuschange.bind(this)
document.addEventListener("focus", focuschange, true)
document.addEventListener("blur", focuschange, true)
window.onresize = this.resizeWindow.bind(this)
}
focuschange(event) {
let target = event.target
let elementType = null
let checkType = false
let checkEnabled = false
let checkEditable = true
if (event.type === "focus") {
elementType = target.nodeName
this.focusElement = target
switch (elementType) {
case "INPUT":
checkType = true
case "TEXTAREA":
checkEditable = false
checkEnabled = true
break
}
if (checkType) {
let type = target.type
switch (type) {
case "color":
case "checkbox":
case "radio":
case "date":
case "file":
case "month":
case "time":
this.focusElement = null
checkEnabled = false
default:
elementType += "[type=" + type +"]"
}
}
if (checkEnabled) {
if (target.disabled) {
elementType += " (disabled)"
this.focusElement = null
}
}
if (checkEditable) {
if (!target.contentEditable) {
elementType = null
this.focusElement = null
}
}
} else {
this.focusElement = null
}
this.changeFocusTime = new Date().getTime()
this.listeners.focuschange.forEach(listener => {
listener(this.focusElement, elementType)
})
}
resizeWindow() {
let screenWidth = screen.width;
let windowHeight = window.innerHeight
let dimensions = {
width: innerWidth
, height: windowHeight
}
let orientation = (screenWidth > screen.height)
? "landscape"
: "portrait"
let focusAge = new Date().getTime() - this.changeFocusTime
let closed = !this.focusElement
&& (focusAge < this.focusDelay)
&& (this.windowHeight < windowHeight)
let opened = this.focusElement
&& (focusAge < this.focusDelay)
&& (this.windowHeight > windowHeight)
if ((this.screenWidth === screenWidth) && this.isTouchScreen) {
// No change of orientation
// opened or closed can only be true if height has changed.
//
// Edge case
// * Will give a false positive for keyboard change.
// * The user has a tablet computer with both screen and
// keyboard, and has just clicked into or out of an
// editable area, and also changed the window height in
// the appropriate direction, all with the mouse.
if (opened) {
this.keyboardchange("shown", dimensions)
} else if (closed) {
this.keyboardchange("hidden", dimensions)
} else {
// Assume this is a desktop touchscreen computer with
// resizable windows
this.resize(dimensions, orientation)
}
} else {
// Orientation has changed
this.resize(dimensions, orientation)
}
this.windowHeight = windowHeight
this.screenWidth = screenWidth
}
keyboardchange(change, dimensions) {
this.listeners.keyboardchange.forEach(listener => {
listener(change, dimensions)
})
}
resize(dimensions, orientation) {
this.listeners.resize.forEach(listener => {
listener(dimensions, orientation)
})
}
addEventListener(eventName, listener) {
// log("*addEventListener " + eventName)
let listeners = this.listeners[eventName] || []
if (listeners.indexOf(listener) < 0) {
listeners.push(listener)
}
}
removeEventListener(eventName, listener) {
let listeners = this.listeners[eventName] || []
let index = listeners.indexOf(listener)
if (index < 0) {
} else {
listeners.slice(index, 1)
}
}
}
window.keyboard = new Keyboard()
})()
<head>
...various JS and CSS imports...
<script type="text/javascript">
document.write( '<style>#footer{visibility:hidden}@media(min-height:' + ($( window ).height() - 10) + 'px){#footer{visibility:visible}}</style>' );
</script>
</head>
if('visualViewport' in window) {
window.visualViewport.addEventListener('resize', function(event) {
if(event.target.height + 30 < document.scrollElement.clientHeight) {
console.log("keyboard up?");
} else {
console.log("keyboard down?");
}
});
}