低版本AngularJs(1.2.12及以下)输入中文完成后不触发ng-model的问题

问题描述

当使用的AngularJs版本低于1.2.13时,使用输入法输入中文无法触发ng-model的双向绑定,此时必须再键入其它任意字符或者使输入框失去焦点,才能正确获取到ng-model的绑定值。
这会对某些使用场景造成一些困扰,如搜索关键字自动补全,列表即时过滤等。

环境说明

  • AngularJs版本:1.2.12及以下
  • chrome浏览器版本:65.0.3325.181(正式版本) (64 位)

解决方案

1. 更换angualrJs版本到1.2.13或以上

1.2.13及以上版本已修复该BUG。
对一个庞大的项目或者老项目来说,贸然更换版本有一定的风险,可能会导致已完成开发功能点不可用,应确保有合格且全面的测试以发现问题并修复,保障线上运行时不会出错。
注意:在更换AngularJs版本时,要考虑到AngularJs相关插件的版本同步更新。

2. 修改源码

AngularJs会为添加了ng-model指令的输入框绑定一系列监听,当input输入框类型为text时,绑定监听的方法为textInputType
textInputType方法中,绑定了compositionstartcompositionendinput的事件监听,这就是对中文输入等非直接输入的监听事件(具体作用可自行搜索),代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
var composing = false;

element.on('compositionstart', function() {
composing = true;
});

element.on('compositionend', function() {
composing = false;
});

var listener = function() {
// composing为true时,直接return,不执行listener
if (composing) return;
var value = element.val();

if (toBoolean(attr.ngTrim || 'T')) {
value = trim(value);
}

if (ctrl.$viewValue !== value) {
scope.$apply(function() {
ctrl.$setViewValue(value);
});
}
};

if ($sniffer.hasEvent('input')) {
element.on('input', listener);
} else {
// 其它代码在此省略
...
}

// 其它代码在此省略
...
}

按代码逻辑来看,预想的是:在键入中文时,触发compositionstart,将composing值修改为true,输入完成触发compositionend,将composing值修改为false,然后触发input,执行listener,完成双向绑定。理想触发顺序为 compositionstart --> compositionend --> input --> 执行listener
但是在chrome浏览器中,由于浏览器机制问题,实际触发顺序为: compositionstart --> input --> 执行listener(实际并未执行)--> compositionend
因此,针对chrome浏览器,我们需要在触发compositionend后,才执行listener,所以,我们可以直接在compositionend方法内部调用listener:

1
2
3
4
element.on('compositionend', function() {
composing = false;
listener();
});

实际上,1.2.13及以上版本就是这么做的。

3. 自定义指令

在某些特殊情况下,如果更换版本、修改源码均不可行,可以考虑自定义指令实现ng-model相同的功能。

4. 更换浏览器

。。。

低版本AngularJs(1.2.12及以下)输入中文完成后不触发ng-model的问题

https://hormones.github.io/post/eaffb42e/

作者

Ethan Davis

发布于

2021-09-12

更新于

2021-09-12

许可协议

评论