这不是一个真实的浏览器事件,不过的确曾经存在这样一个事件满足我们的需求。
很多时候,我们需要对文本域的值进行变化检测,不论是这变化是用户通过键盘敲打引发的,或是通过el.setAttribute("value","aaa")引发的,还是el.value = "bbb"引发的,还是用户通过复制粘贴引发的,更恶心的是HTML通过语音输入引发的。只要里面的文字发生变化,我们希望都能比较及时调用相应的程序进行处理。
在旧式IE(IE6-8)下,onpropertychange可以满足上述所有需求(由于IE不支持input[speed]),因此不用考虑最后一种输入)。
IE9开始区分attribute和property了,从许多场合来是好事,但在这场合则是坏事,它相当于DOM3变动事件中的DOMAttrModified。只对用户输入与setAttribute见效,不支持直接赋值方式的检测。
标准浏览器也提供了一个input,但它也不支持直接赋值方式的检测。即便最新式的mutationObserver API,对el.value ="zzz"这种属性赋值法也无济于事。因此自己动手富衣足食。
取一个文本域的值最简单不过,对两个字符串进行比较也最简单不过。我们要做的是得到先后两个值。因此需要用最通用的事件进行冒允。当我们在PC上输入内容,肯定会触发mousedown事件,也肯定触发mousedown。进行输入时确定会触发键盘事件,根据我的知识库,keypress会对一些系统键失灵,因此最好用keyup,keydown。但用户不一定通过键盘输入,HTML5还提供了语音输入,只要点了那个麦风筒图案就可以口述了,麦风筒也在input上,因此mousedown肯定也有。当我们输入后肯定会继续其他表单元素的填写或进行提交,因此会触发blur事件。从mousedown到blur这段时间,我们可以通过定时器加keydown, keyup, webkitspeechchange的回调进行值变化判定,变化了就执行用户回调,把前后两个值放到事件对象中。
下面是mass Framework的实现:
define(
"valuechange"
, [
"$event"
],
function
(){
var
DATA =
"valuechangeData"
;
var
ID =
"valuechangeID"
var
interval = 50;
//如果值前后发生改变,触发绑定回调
function
testChange(elem, type, poll) {
if
(poll){
$._data(elem, ID, setTimeout(
function
(){
testChange(elem, type, poll);
},interval));
}
var
old = $._data(elem, DATA);
var
neo = elem.value;
if
(old !== neo){
$._data(elem, DATA, neo);
var
event =
new
$.Event(
"valuechange"
)
event.oldType = type
event.oldValue = old;
event.newValue = neo;
$.event.fire.call(elem, event)
}
}
function
unTestChange(elem){
var
id = $._removeData(elem, ID)
clearTimeout( id )
$.log($._removeData)
$._removeData(elem, DATA);
}
function
startTest(event) {
var
elem = event.target;
if
(event.type ==
'focus'
) {
$._data(elem, DATA , elem.value);
}
testChange(elem,event.type,
true
);
}
function
stopTest(event){
unTestChange(event.target)
}
function
listen(elem) {
unlisten(elem);
"keydown keyup mousedown focus"
.replace($.rword,
function
(name){
$(elem).bind(name+
"._valuechange"
, startTest)
})
$(elem).bind(
'blur._valuechange'
, stopTest);
$(elem).bind(
'webkitspeechchange._valuechange'
,
function
(e){
testChange(e.target,e.type)
});
}
function
unlisten(elem){
unTestChange(elem)
$(elem).unbind(
"._valuechange"
)
}
$.fn.valuechange =
function
(callback){
return
callback?
this
.bind(
"valuechange"
, callback ) :
this
.fire(
"valuechange"
);
}
$.eventAdapter.valuechange = {
setup:
function
(desc){
var
elem = desc.currentTarget, nodeName = elem.tagName;
if
(nodeName ==
'INPUT'
|| nodeName ==
'TEXTAREA'
) {
listen(elem);
return
false
}
},
tearDown:
function
(desc) {
unlisten(desc.currentTarge);
return
false
}
}
})
|
它的事件系统的架构与jQuery的很相近,都是通过setup, teardown方法来绑定特殊的事件。我们只对INPUT元素及文本区进行操作,一定进入分支,就调用listen监听函数。接下来绑定的事件的作用依次是:
具体例子可见这里。
有了这个onvaluechange事件,以后做表单验证或自动完成及MVVM的输入双向绑定就轻松多了。