В качестве фронтенд-разработки неизбежно контактировать с входными данными в работе и выполнять некоторую индивидуальную разработку на основе входных данных, но из-за различий между системами Android и ios выбор веб-просмотра хост-приложения (в частности, ios), историческое наследие приложения и т. д., будет много проблем с совместимостью
Ниже я буду записывать проблемы и решения, с которыми я столкнулся в процессе разработки, в надежде помочь вам.
1. тип веб-просмотра ios
Встроенные веб-просмотры разных приложений в iOS могут отличаться, что приводит к непоследовательному поведению при вводе, поэтому давайте сначала рассмотрим общий вид.В настоящее время в системе ios существует два типа веб-просмотров: WK и UI.
До ios8 использовался пользовательский интерфейс, но начиная с ios8 был добавлен тип WK.По сравнению с UI, WK загружается быстрее, потребляет меньше памяти и поддерживает больше функций h5, поэтому крупные компании в основном будут это обновление, но это не исключить, что некоторые приложения все еще используют пользовательский интерфейс по разным историческим причинам. Например, наша страница h5 в настоящее время работает в нескольких приложениях с пользовательским интерфейсом и WK. Естественно, мы примем некоторые решения о совместимости во время разработки.
Определить тип веб-просмотра
// 暂没发现好的方法来判断webview的类型,除非ios开发告诉你
// 下面这个方式是通过某些只有wk支持的h5新特性来判断
function getIosWebviewType() {
if (navigator.platform.substr(0, 2) === 'iP') {
// iOS (iPhone, iPod or iPad)
const lte9 = /constructor/i.test(window.HTMLElement);
const nav = window.navigator; const ua = nav.userAgent;
const idb = !!window.indexedDB;
if (ua.indexOf('Safari') !== -1 && ua.indexOf('Version') !== -1 && !nav.standalone) {
return 'Safari'
} else if ((!idb && lte9) || !window.statusbar.visible) {
return 'UI'
} else if ((window.webkit && window.webkit.messageHandlers) || !lte9 || idb) {
return 'WK'
}
}
return 'unknown'
}
2. Автофокус не работает
Будь то спецификация h5 или проверка caniuse, этот атрибут поддерживается, но когда вы тестируете его на реальной машине, во многих случаях это не тот эффект, который вам нужен.
В настоящее время мой тест выглядит следующим образом:
- ios
- UIWebview, может фокусироваться, имеет курсор, может вызывать клавиатуру
- WKWebview, может фокусироваться, имеет курсор, но не может вызывать клавиатуру
- андроид
- На данный момент проблем не обнаружено (но не совсем)
Причина, которую я узнал в Интернете, заключается в том, что Apple хочет, чтобы пользователь срабатывал, и ввод этой операции является волей пользователя, а не принудительным, поэтому этот атрибут запрещен в новой версии системы, а старая версия пользовательский интерфейс не имеет этого ограничения.
Но, к счастью, и Android, и ios поддерживают синхронное выполнение input.focus() в событиях touch или click для фокусировки и вызова клавиатуры.
Если бизнес-сценарий подходит к этой ситуации, то можно сделать так
onClick = () => {
this.input.focus()
}
Однако, если в событии щелчка есть асинхронная операция, такая же, как и в атрибуте автофокуса, то фокус может быть только на нем, а не на клавиатуре.
onClick = () => {
setTimeout(() => {
this.input.focus()
}, 1000)
// 或者
fetch('/api/get').then(() => {
this.input.focus()
})
}
Обработка понижения версии
Если бизнес-сценарий не соответствует вышеуказанной ситуации, но это не для этой функции, есть решение для укрепления эффекта фокусировки (потому что нативный курсор не очевиден)
- Установите стиль фокуса или, на других элементах страницы или по собственному решению о функциях продукта и ввода UE
- Соответствующим образом прокрутите страницу так, чтобы она находилась в середине представления.
3. Сосредоточьтесь на проблеме
3.1 Щелчок не может сфокусироваться или сфокусироваться, а затем потерять фокус
Большинство случаев вызвано проблемой 300 мс на мобильном терминале.
Один из них: приложение использует UIWebview, но страница h5 не использует fastclick.
Другой - это: введение FastClick, но надо сосредоточиться на FastClick, оптимизированным вместо
FastClick.prototype.focus = function (targetElement) {
targetElement.focus();
};
3.2 Курсор не может сфокусироваться на месте щелчка
Эта высокая вероятность также вызвана быстрым кликом, см.:Связь
3.3 Нажмите на другой вход, когда он сфокусирован, он перепрыгнет
Эта высокая вероятность также вызвана быстрым кликом, перейдите по ссылке выше.
Или измените исходный код fastclick следующим образом, добавьте новое суждение в onTouchEnd, нужно ли вам следовать собственной логике фокуса.
FastClick.prototype.onTouchEnd = function (event) {
// ...
if (targetTagName === 'label') {
// ...
} else if (this.needsFocus(targetElement)) {
// 新增
if (!this.needsFocusInput()) return false
// ...
}
// ...
};
// 新增
// 已有聚焦元素的情况下,直接走原生input聚焦逻辑
FastClick.prototype.needsFocusInput = function () {
const focusInput = document.querySelector('input:focus')
return !focusInput
}
Рекомендация 3.4.
Большинство вышеперечисленных проблем вызваны fastclick, но проблема, решаемая fastclick (300 мс), в настоящее время решена большинством браузеров, поэтому убедитесь, что если ваше приложение не использует UIWebview, вы можете напрямую удалить fastclick.
Описание fastclick на гитхабе:
Note: As of late 2015 most mobile browsers - notably Chrome and Safari - no longer have a 300ms touch delay, so fastclick offers no benefit on newer browsers, and risks introducing bugs into your application. Consider carefully whether you really need to use it.
4. Проблема не в фокусе
4.1 Хотите оставаться сосредоточенным
Иногда вы хотите, чтобы ввод оставался сфокусированным, когда вы щелкаете в другом месте страницы, но поведение браузера по умолчанию состоит в том, чтобы расфокусировать ввод.
Решение: в событии щелчка, чтобы предотвратить поведение по умолчанию
function onClick(e) {
// 你的事件处理代码
...
e.preventDefault();
// iphone有的机型下,没有阻止掉默认行为,主动再聚焦一下
input.focus();
}
4.2 Надежда активно терять фокус
Некоторые модели Android имеют следующие проблемы
- В случае фокуса щелкните в другом месте страницы, не теряя фокуса.
- В некоторых случаях, после активного скрытия клавиатуры, ввод не теряет фокус, но когда пользователь касается других частей страницы, клавиатура будет вызвана, потому что ввод по-прежнему находится в фокусе
Целевые решения также делятся на два
Первый: прислушиваться к поведению пользователя, активно вниз
const autoBlur = (e) => {
const target = e.target
const { tagName, className } = target
// 点击非input区域
if (tagName.toUpperCase() !== 'INPUT') {
this.input.blur()
}
}
document.body.addEventListener('touchstart', autoBlur)
Второй: следить за изменением высоты клавиатуры и активно расфокусировать
const onKeyboardChange = (resize) => {
// 有时候,比如number变成text,或者系统自动在键盘上面加一些装饰,键盘并没有隐藏,但是触发了resize
// 测试大部分机型,所有的键盘肯定大于120高度了,所以加一个限制
if (Math.abs(resize) < 120) return
const show = resize > 0
if (!show) {
this.input.blur()
}
}
function getClientHeight() {
return document.documentElement.clientHeight || document.body.clientHeight;
}
// 记录原始高度
let originHeight = getClientHeight()
// 监听键盘变化
window.addEventListener('resize', () => {
const resizeHeight = getClientHeight()
const resize = originHeight - resizeHeight
onKeyboardChange(resize);
originHeight = resizeHeight;
}, false)
5. Прокрутите изображение после фокусировки
В большинстве случаев система поможет вам прокрутить ввод в представление, в некоторых случаях нам нужно установить его самостоятельно
-
Одним из решений является прямой вызов API-интерфейса scrollIntoViewIfNeeded.
-
Другой - вычислить разницу между высотой документа до и после фокусировки, затем соответственно увеличить высоту тела и установить scrollTop, который должен отображаться в UIWebview.
// 正常处理
input.addEventListener('focus', () => {
setTimeout(() => {
this.input.scrollIntoViewIfNeeded();
}, 300)
})
// UIWebview下的处理
function getClientHeight() {
return document.documentElement.clientHeight || document.body.clientHeight;
}
const bodyHeight = getClientHeight()
const bodyOverflow = getComputedStyle(document.body).overflow
input.addEventListener('focus', () => {
document.body.style.overflow = 'auto'
setTimeout(() => {
// alert(getClientHeight())
let height = bodyHeight - getClientHeight()
if (height < 0) height = height * -2
document.body.style.height = `${bodyHeight + height}px`;
document.body.scrollTop = height;
}, 300)
})
// 如果设置了高度,在blur时要设置回来
input.addEventListener('blur', () => {
document.body.style.height = `${bodyHeight}px`;
document.body.style.overflow = bodyOverflow
})
Добавление setTimeout связано с тем, что будет анимация при возбуждении клавиатуры, нам нужно прокручивать страницу после окончания анимации, иначе вычисленная высота будет неточной.
В большинстве случаев менее 300 анимированных клавиатур
6. Принудительно завершить курсор
input.addEventListener('touchend', e => {
const length = e.target.value.length
e.target.setSelectionRange(length, length);
e.preventDefault()
e.target.focus()
})
7. Некоторые другие вопросы
7.1 Скрытие курсора
В некоторых сценариях вам необходимо настроить поле ввода, настроить курсор и т. д.
Android может скрыть родной курсор через opacity: 0; color: Transparent и т. д.
Но ios не может скрыть это, он может только переместить поле ввода за пределы представления, сначала установить достаточно большую ширину ввода, а затем переместить его влево:
input {
width: 1000px;
margin-left: -200px;
}
7.2 Скопируйте и вставьте
И Android, и ios поддерживают копирование и вставку при длительном нажатии, но предпосылка ios заключается в том, что курсор должен находиться в представлении.После перемещения ввода влево, как указано выше, кнопка вставки не отображается в представлении и не может быть вставлена.
7.3 SMS-код подтверждения (или другие цифры), отображаемые на системной клавиатуре
В новой версии ios (должно быть 12+, не уверен) система будет сразу отображать текстовое сообщение на клавиатуре после получения текстового сообщения, и пользователь может ввести ввод в один момент, но старая версия этого не поддерживает , и пользователь должен проявить инициативу, чтобы скопировать текстовое сообщение, а затем вставить его во ввод, если ввод является пользовательским, вам необходимо обратить внимание на вышеуказанные проблемы.
Некоторые машины Android (например, Xiaomi Mi 6+) получают текстовое сообщение, вы можете напрямую щелкнуть панель уведомлений, чтобы скопировать его, и оно также появится на клавиатуре, в то время как другие модели требуют, чтобы пользователь долго нажимал и вставлял
8. Заключение
Выше перечислены в основном проблемы, с которыми я столкнулся в процессе разработки.При итеративном обновлении системы многие проблемы будут официально решены, но мы не можем решить, обновлять ли приложение или нет, и мы не можем решить, обновлять ли пользователя.
Итак, если вы также столкнетесь с этими проблемами, я надеюсь вдохновить вас и помочь