textarea实时字数统计必须用oninput事件并过滤composition状态,配合手动截断和UTF-8字节计算,同时确保DOM结构与事件绑定时机正确。
change 事件只在失焦后触发,粘贴、中文输入、连续删除都不会响应——字数统计会严重滞后。oninput 才是唯一能覆盖所有输入场景的原生事件。
但要注意:中文输入法在「拼音组合中」(比如刚敲下“zhong”,还没选“中”)也会触发 oninput,此时 value 是拼音串,长度不准。必须加 e.isComposing === false 过滤:
textarea.addEventListener('input', function(e) {if (e.isComposing) return;const val = this.value;// 后续做长度判断和截断});
onkeyup:无法捕获鼠标粘贴、拖入文本onpropertychange:IE 专属,现代浏览器已废弃maxlength="100" 在多数浏览器里能阻止部分超长输入,但对粘贴、拖放、中文输入法上屏前的内容完全无效。Layui 的 .layui-textarea 类也不干预这个行为,所以必须手动截断。
关键逻辑是:检测到超长后,立刻重赋值,否则 DOM 和实际内容不同步,光标会跳到末尾或重复触发:
if (val.length > maxLen) {this.value = val.slice(0, maxLen);}
this.setAttribute('maxlength', maxLen) 动态设置——旧版 Safari 不支持运行时生效new TextEncoder().encode(val).length,而不是 val.length
用户用拼音打「中国」时,「zhongguo」还在组合中,这时直接截断会清空输入框或卡死。正确做法是暂停截断逻辑,等输入法确认上屏后再检查:
let isComposing = false;textarea.addEventListener('compositionstart', () => isComposing = true);textarea.addEventListener('compositionend', () => {isComposing = false;// 此时再执行长度校验});// oninput 回调里加 if (isComposing) return;
compositionend 不够:用户中途取消输入(ESC)不会触发它,得靠 compositionstart 标记状态compositionstart 里清空 value 或重置光标——会打断输入流程paste)需用 setTimeout(() => { /* 读取 value */ }, 0),因为粘贴内容在事件回调里尚未写入 DOM计数字数的 <div class="word"> 必须放在 .layui-input-block 内部,并且该容器要设 position: relative,否则绝对定位的数字会飘到页面角落:
.layui-input-block { position: relative; }.word { position: absolute; right: 10px; bottom: 8px; font-size: 12px; color: #999; }
$(textarea).next('.word').text(`${curr}/${max}`),别用 $('.word') 全局匹配——多个 textarea 会互相覆盖.word 元素在绑定事件前已存在,否则 .next() 返回空edit: "textarea":它不透传 maxlength,也不支持自定义事件,得改用 templet 手动渲染 textarea真正容易被忽略的是 composition 状态管理——没它,中文输入体验就崩了;还有动态插入场景下元素顺序和事件绑定时机,一错就整个字数统计失效。