1.input与输入延迟更新
先来看Vue给input正常绑定的回调
input: function($event) {
// 这里就是延迟更新的重点
// 当composing=true时,事件回调不会走到下面的更新操作
if ($event.target.composing) return;
name = $event.target.value;
}
Vue会给input和textarea绑定以下事件
- compositionstart
- compositionend
- change
compositionstart
会在input事件触发之前触发,但是如果我们输入一些中文字符(这些字符还未真实的进入输入框)
时,是不会触发compositionstart
事件的。
function onCompositionStart(e) {
// 这就避免了当我们输入拼音是,触发不必要的input事件
e.target.composing = true;
}
function onCompositionEnd(e,eventname) {
if (!e.target.composing) { return }
e.target.composing = false;
trigger(e.target, 'input');
}
为了兼容iOS<10.2
等那些不会触发compositionend
的浏览器,Vue监听了change时间来代替。
以上这些事件都是在inserted
钩子中进行绑定的。
function inserted(el, binding, vnode, oldVnode) {
// isTextInputType判断 input 是不是 text,number,password,search,email,tel,url其中一个
if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
el._vModifiers = binding.modifiers;
// 如果设置 v-model.lazy,那么不处理 预输入的问题
if (!binding.modifiers.lazy) {
el.addEventListener('compositionstart', onCompositionStart);
el.addEventListener('compositionend', onCompositionEnd);
el.addEventListener('change', onCompositionEnd);
}
}
}
2. Range类型的input
为了兼容IE,所以在解析的时候先保存_r事件,后面开始绑定的时候,判断浏览器而决定用什么事件
function genDefaultModel(
el, value, modifiers
){
var type = el.attrsMap.type;
var ref = modifiers || {};
var lazy = ref.lazy;
// 这里省略了lazy 的判断啦
var event = type === 'range' ? "__r" :'input';
code = "if($event.target.composing)return;"
+ value+"=$event.target.value";
addProp(el, 'value', ("(" + value + ")"));
addHandler(el, event, code, null, true);
}
function updateDOMListeners(oldVnode, vnode) {
var on = vnode.data.on
if (isDef(on["__r"])) {
var event = isIE ? 'change': 'input';
on[event] = [].concat(on["__r"], on[event] || []);
delete on["__r"];
}
for (name in on) {
vnode.elm.addEventListener(name, on[name]);
}
}
3.v-model.lazy
当v-model设置了lazy的时候,会绑定change而不是input,延时更新的意思
function genDefaultModel(
el, value, modifiers
){
var ref = modifiers || {};
var lazy = ref.lazy;
// 省略了 range 类型的判断
var event = lazy ? 'change' :'input';
addHandler(el, event, code, null, true);
}
Vue默认为input等输入类型的表单绑定input事件,如果设置延迟更新,就相当于改变了内容,是去焦点才触发。
4. v-model.trim v-model.number
function genDefaultModel(
el, value, modifiers
){
var ref = modifiers || {};
var number = ref.number;
var trim = ref.trim;
// 去首尾空格
if (trim) {
valueExpression = "$event.target.value.trim()";
}
// 转成数字
if (number) {
valueExpression = "_n(" + valueExpression + ")";
}
code = "if($event.target.composing)return;" +
value+"="+valueExpression;
addProp(el, 'value', ("(" + value + ")"));
addHandler(el, "input", code, null, true);
if (trim || number) {
addHandler(el, 'blur', '$forceUpdate()');
}
}
看下最终生成的回调
// v-model.trim
function($event) {
if ($event.target.composing) return;
name = $event.target.value.trim();
}
// v-model.number
function($event) {
if ($event.target.composing) return;
name = _n($event.target.value);
}
这两个还会额外绑定一个blur
时间,用来$forceUpdate