IE8 不支持 oninput,必须用 onpropertychange 替代,但需过滤 propertyName、防递归触发、处理 disabled 失效及 JS 赋值场景,contenteditable 和 textarea 需轮询兜底。
答案是肯定的:IE8 完全不支持 oninput,因此必须改用 onpropertychange。不过,直接替换容易遇到问题,包括 JS 赋值不触发、使用输入法时重复触发,以及失去焦点后依然误触发等。
IE8 无法识别 oninput 完成事件绑定后也不会产生响应。官方文档与实际测试均已确认:能够监听的只有 onpropertychange 可用于监听 value 变化的是属性。不过,它面向“任意属性变更”,并非针对输入而设计,因此表现得更加粗粒度:
onpropertychange 当 value、className、disabled 等任意属性被改写时都会触发,所以需要手动进行过滤event.propertyName === 'value' 判断触发原因是否确实是输入input.value = 'xxx' 时会触发,而这一点 oninput 无法做到(原生 oninput 不会响应脚本赋值)disabled=true,onpropertychange 便会失效 —— 这一点经常遭到忽略若直接写在 HTML 中 onpropertychange="handler()" 或者采用 element.onpropertychange = handler 均可能造成递归调用(例如 handler 内再次修改 value)。应采用以下正确方式:
attachEvent('onpropertychange', handler)(IE8 专属),不要采用 DOM0 级绑定if (event.propertyName !== 'value') return;
input.value,不然可能开启新一轮 onpropertychange
input._skipPropertyChange = true; input.value = 'x'; input._skipPropertyChange = false;,再由 handler 将其跳过只使用原生 JS 判断运行环境并完成分发,无须框架,也不引入 polyfill:
function bindInputEvent(el, callback) { if ('oninput' in el) { el.addEventListener('input', callback, false); } else if ('onpropertychange' in el) { el.attachEvent('onpropertychange', function(e) { if (e.propertyName === 'value') callback.call(el, e); }); }}// 使用bindInputEvent(document.getElementById('myInput'), function() { console.log('value changed:', this.value);});
需要注意,该方案不会处理输入法(compositionstart/update/end)。若要完整支持中文输入,就必须叠加监听这些事件 —— 但 IE8 自身并不支持 composition 事件,因此对于 IE8,onpropertychange 已经属于底线方案。
真正经常遭到忽视的是:在 IE8 中 onpropertychange 针对 contenteditable 元素不起作用,对 textarea 的换行符变化也无法稳定响应。业务若涉及富文本编辑,仅依赖这个事件远远不够,必须降级为定时轮询 setInterval 通过检查 value 是否变化来兜底 —— 这种方法虽然效率较低,却是 IE8 环境下确实可用的保障手段。