文字输入限制
知识点
直接文字输入
输入英文、符号等直接显示在输入框中的字符称为直接文字输入
非直接文字输入
输入中文时是非直接文字输入,只有选中文字之后才算正式输入,非直接文字输入开始及结束时会相应的触发compositionstart, compositionend事件
max-length属性只针对直接文字输入
要求
- 输入限制8个字
- 实时检查是否达到限制字数,alert提醒
常见的解决方案
- 设置input元素的maxlength属性
监听keydown, input事件
$('#input').on('input', function(e) { console.log('input') const len = $(this).val().length if (len > 8) { alert('input more than 8') } })
存在问题
非直接文字输入
假如我们要起名字:“思超煎饼”,那么完整输入流为:si’chao’jian’bing,但是上面的实现方案在输入到 si’chao’j 就会触发alert,从而导致用户输入中断,此时输入框内容为 si’chao’j, 用户只能一个字一个字的输入才能成功,用户体验很差。
emoji表情输入
当输入emoji表情时,Android和PC端中 maxlength 判断emoji表情的length为2,因此正常情况下emoji最多4个,但是在iOS端中maxlength对 emoji长度判定为1,导致多端体验不同
解决方案
为了防止emoji表情的判断问题,不使用maxlength属性,使用js判断长度
- 针对非直接文字输入,使用compositionstart, compositionend, input事件监听输入框, 前两个事件判断当前是否为直接文字输入,选中文本之后如果超过字数限制时截取前8个字符
代码
// html
<input id="input"></input>
// js
const setCutTxt = (element, txt, start, end) => {
element.val(txt.substring(start, end))
}
let compositioning = false
$('#input').on('compositionstart', function(e) {
compositioning = true
})
$('#input').on('compositionend', function(e) {
compositioning = false
if (e.target.value.length > 8) {
setCutTxt($(e.target), $(e.target).val(), 0, 8)
window.alert('input more than 8')
}
})
$('#input').on('input', function(e) {
if (!compositioning) {
log(e.target.value.length)
if (e.target.value.length > 8) {
setCutTxt($(e.target), $(e.target).val(), 0, 8)
window.alert('input more than 8')
}
}
})
有一点要注意的是:在iOS端搜狗输入法输入中文时不会触发compositionstart和compositionend事件,自带输入法则会触发。
输入框位置问题
知识点
在iOS中,唤起键盘后,页面会被键盘压缩,即页面高度变小,同时,页面中所有position为fixed的元素变为absolute。
要求
- 将输入框固定在屏幕下方
- 键盘唤起时固定在键盘上方
常见方案
// html
<style>
input {
position: fixed;
left: 0;
bottom: 0;
}
</style>
<input id="input"></input>
存在问题
在iOS端,键盘弹起时,fixed失效,变为absolute,所以弹起的键盘会遮住输入框
解决方案
- 键盘未唤醒时使用div模拟一个假输入框,使用定位隐藏真的输入框(position: absolute)
- 点击div时,聚焦真输入框并将定位到键盘上方
注意事项
真输入框的位置计算
- 页面载入时记录此时的 window.innerHeight
- 唤醒键盘之后再获取此时的 window.innerHeight, 得到键盘高度
- 设置真输入框:left: 0; bottom: 键盘高度;
键盘弹起和收起需要一定的时间
- 键盘弹起计算高度的时候要使用setInterval定时监听innerHeight高度
- 键盘收起时同样要使用setInterval监听
iOS中获取焦点不能使用click事件,而是tap事件
$('#input').on($.os.ios ? 'tap' : 'click', () => {})