Vue input原理分析

1.input与输入延迟更新

先来看Vue给input正常绑定的回调

input: function($event) {
    // 这里就是延迟更新的重点
    // 当composing=true时,事件回调不会走到下面的更新操作
    if ($event.target.composing) return;
    name = $event.target.value;
}

Vue会给input和textarea绑定以下事件

  1. compositionstart
  2. compositionend
  3. 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值