У меня есть непродуманное решение этой проблемы, и я надеюсь, что у других уже могут быть более надежные решения.
На сенсорном экране нажатие на редактируемое текстовое поле приведет к появлению экранной клавиатуры, и это изменит объем доступного пространства экрана. Если вы не лечите, это может скрыть ключевые элементы или нажать нижний колонтитул на место.
На ноутбуке или настольном компьютере открытие редактируемого текстового поля не создает таких изменений макета.
В моем текущем проекте я хочу убедиться, что некоторые ключевые элементы видны, даже когда виртуальная клавиатура открыта, поэтому мне нужно определить, когда произойдет такое изменение. Затем я могу добавить класс в элемент body
, чтобы изменить макет в соответствии с наличием клавиатуры.
При поиске существующих решений в Интернете я обнаружил, что:
contentEditable
откроют экранную клавиатуруЯ опубликовал решение, которое я привел ниже. Он основан на обнаружении изменения высоты окна в течение секунды изменения фокуса клавиатуры. Я надеюсь, что у вас может быть лучшее решение, предлагающее протестировать кросс-платформенный, кросс-браузер и все устройства.
Я создал репозиторий на GitHub.
Вы можете проверить мое решение здесь.
В моих тестах это может привести к ложному срабатыванию, если пользователь использует компьютер с сенсорным экраном и клавиатурой и мышью, а сначала использует мышь (de-), выбирает редактируемый элемент, а затем сразу же изменяет высоту окна. Если вы обнаружите другие ложные срабатывания или негативы, будь то на компьютере или мобильном устройстве, пожалуйста, дайте мне знать.
;(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()
})()
Это трудная проблема, чтобы получить "право". Вы можете попытаться скрыть нижний колонтитул на фокусе элемента ввода и показать размытие, но это не всегда надежно на iOS. Каждый раз так часто (один раз в десять, скажем, на моем iPhone 4S) фокусное событие, похоже, не срабатывает (или, может быть, есть состояние гонки с JQuery Mobile), а нижний колонтитул не скрывается.
После долгих проб и ошибок я придумал это интересное решение:
<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>
По существу: используйте JavaScript, чтобы определить высоту окна устройства, а затем динамически создайте мультимедийный запрос CSS, чтобы скрыть нижний колонтитул, когда высота окна уменьшается на 10 пикселей. Поскольку открытие клавиатуры изменяет размер экрана браузера, это никогда не прерывается в iOS. Поскольку он использует механизм CSS, а не JavaScript, он намного быстрее и плавнее!
Примечание. Я обнаружил, что "видимость: скрытая" менее глючная, чем "display: none" или "position: static", но ваш пробег может отличаться.
Поскольку нет прямого способа обнаружить открытие клавиатуры, вы можете определять только по высоте и ширине. Узнать больше
В javascript screen.availHeight
и screen.availWidth
может помочь.
screen.availHeight
иscreen.availWidth
чтобы обнаружить изменения размера экрана. Я тоже это нашел