摘要:因?yàn)槭ソ裹c(diǎn)之后被強(qiáng)制更新了一波嗯,這就是的作用,把頁(yè)面上的顯示值也過(guò)濾一遍
寫文章不容易,點(diǎn)個(gè)贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧
研究基于 Vue版本 【2.5.17】
如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧
【Vue原理】VModel - 源碼版之input詳解
上一篇文章,我們大概講了所有表單元素的雙綁原理,但是仍然有兩個(gè)特殊的表單元素,是要多更多處理的,也不可能放在一篇文章說(shuō)完,今天,我們說(shuō)的是 input 的特殊處理的地方
而 input 有什么特殊處理的地方呢?
1、預(yù)輸入延遲更新
2、range 類型的 input
3、v-model.lazy
4、v-model.trim、v-model-number
預(yù)輸入延遲更新先來(lái)看看Vue 給 input 正常綁定的回調(diào)
input: function($event) { if ($event.target.composing) return; name = $event.target.value }
看到我標(biāo)紅的地方,這句話就是完成預(yù)輸入延遲更新的重點(diǎn)
當(dāng)composing=true時(shí),事件回調(diào)不會(huì)走到下面的更新操作,而 Vue 正式通過(guò)這個(gè)標(biāo)志位,判斷現(xiàn)在是否是預(yù)輸入而確定是否需要實(shí)時(shí)更新
首先,Vue 會(huì)為 input 或者 textarea 綁定以下事件
compositionstart
compositionend
change
開始講解這三個(gè)事件了
1、compositionstart
首先,compositionstart 會(huì)在 input 事件觸發(fā)之前 觸發(fā)
but!你打一些直接輸入的字符,是不會(huì)觸發(fā) compositionstart 的,只會(huì)觸發(fā) input
只有打預(yù)輸入的字符才會(huì)觸發(fā),比如 輸入拼音,不行看圖
輸入普通字符
預(yù)輸入延遲更新下,輸入拼音
取消預(yù)輸入延遲更新,輸入拼音
看完上面的動(dòng)圖,預(yù)輸入延遲更新什么用,估計(jì)你心里也有點(diǎn)逼數(shù)了吧?
為什么要做預(yù)輸入延遲更新?
如果不做!在輸入拼音的時(shí)候,每打一個(gè)拼音字母都會(huì)觸發(fā) input 事件,但是我們根本還沒(méi)往表單中寫入我們預(yù)想中的東西
而此時(shí)觸發(fā) input 事件沒(méi)有任何意義,因?yàn)檫€不是我們要輸入的值,這是一個(gè)浪費(fèi)的操作
剛好,compositionstart 在 input 之前觸發(fā),而且只會(huì)預(yù)輸入才觸發(fā)
所以!就可以通過(guò)一個(gè)標(biāo)志位來(lái)控制 input 回調(diào)導(dǎo)致的更新就再好不過(guò)了!
怎么做呢?看 compositionstart 回調(diào)源碼
function onCompositionStart(e) { e.target.composing = true; }
2、compositionend
在打完預(yù)輸入的字符之后,會(huì)觸發(fā)
在預(yù)輸入延遲更新中起什么作用呢?
預(yù)輸入結(jié)束,肯定是設(shè)置 composing 為 false了,看源碼
function onCompositionEnd(e,eventname) { if (!e.target.composing) { return } e.target.composing = false; trigger(e.target, "input"); }
還會(huì) 手動(dòng)觸發(fā) input 事件去 執(zhí)行更新操作哦
trigger 是什么?也是很簡(jiǎn)單的,值得收藏的源碼,不解釋了
function trigger(el, type) { var e = document.createEvent("HTMLEvents"); e.initEvent(type, true, true); el.dispatchEvent(e); }
3、change
為了兼容Safari<10.2 等那些 不會(huì)觸發(fā) compositionend 的瀏覽器(Vue自己注釋說(shuō)的,我沒(méi)有測(cè)過(guò)),于是監(jiān)聽(tīng) change事件,來(lái)代替 compositionend 的功能
change 的回調(diào) 和 compositionend 的回調(diào)是一樣的,因?yàn)橹皇且粋€(gè)備胎功能
4、 他們?cè)谀睦镩_始綁定這些事件呢?
你應(yīng)該必須知道,指令都是有生命鉤子函數(shù)的,而這幾個(gè)事件正是在 inserted 鉤子中進(jìn)行綁定的
Vue 官方文檔說(shuō)明 inserted
看下 inserted 鉤子函數(shù)
function inserted(el, binding, vnode, oldVnode) { // isTextInputType判斷 input 是不是 text,number,password,search,email,tel,url其中一個(gè) if (vnode.tag === "textarea" || isTextInputType(el.type)) { el._vModifiers = binding.modifiers; // 如果設(shè)置 v-model.lazy,那么不處理 預(yù)輸入的問(wèn)題 if (!binding.modifiers.lazy) { el.addEventListener("compositionstart", onCompositionStart); el.addEventListener("compositionend", onCompositionEnd); el.addEventListener("change", onCompositionEnd); } } }
TIP
inserted 鉤子中,還處理了 select ,但是這里是input的版塊,所以去掉了,放在下篇文章講
Range 類型 Input為了兼容 IE,所以在解析的時(shí)候,先保存的是 __r 事件,后面開始綁定的時(shí)候,判斷瀏覽器而決定使用什么事件
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); }
看到我加藍(lán)加粗的地方,就是為 range 特別處理的地方,綁定 __r 事件
判斷瀏覽器,轉(zhuǎn)換事件的函數(shù)updateDOMListeners源碼
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]); } }v-model.lazy
當(dāng)你的 v-model 設(shè)置了 lazy 的時(shí)候,會(huì)綁定 change 而不是 input,延時(shí)更新的意思
function genDefaultModel( el, value, modifiers ){ var ref = modifiers || {}; var lazy = ref.lazy; // 省略了 range 類型的判斷 var event = lazy ? "change" :"input"; addHandler(el, event, code, null, true); }
我們都知道,為了輸入實(shí)時(shí)響應(yīng),vue 默認(rèn)為 input 等輸入類型的 表單 綁定 input 事件,讓 input
如果你設(shè)置延遲更新,就是相當(dāng)于你改變了內(nèi)容,然后失去焦點(diǎn)才觸發(fā)
v-model.trim、v-model.number如果你給 v-model 設(shè)置了值過(guò)濾,像 trim 去掉首尾空格,number 把值變成數(shù)字
function genDefaultModel( el, value, modifiers ){ var ref = modifiers || {}; var number = ref.number; var trim = ref.trim; // 去首尾空格 if (trim) { valueExpression = "$event.target.value.trim()"; } // 轉(zhuǎn)成數(shù)字 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()"); } }
對(duì)于 trim 和 number,Vue 會(huì)對(duì)表單值做處理,你可以看到源碼中
trim:值會(huì)調(diào)用 trim 方法
number:會(huì)調(diào)用 _n 轉(zhuǎn)換成數(shù)字方法
看下最終的回調(diào)
function($event){
if($event.target.composing)return; name=_n($event.target.value);
}
function($event){ if($event.target.composing)return; name=$event.target.value.trim(); }
這兩個(gè)鬼東西,還會(huì)額外綁定一個(gè)事件 blur
看下回調(diào) $forceUpdate,這個(gè)函數(shù)作用是強(qiáng)制更新頁(yè)面
為什么要更新頁(yè)面?給個(gè)動(dòng)圖看好吧
我設(shè)置了 trim,然后輸入的時(shí)候,故意多加幾個(gè)空格,然后失去焦點(diǎn)(觸發(fā)設(shè)置的 blur),再點(diǎn)發(fā)現(xiàn)空格不見(jiàn)了。因?yàn)槭ソ裹c(diǎn)之后被強(qiáng)制更新了一波
嗯,這就是 $forceUpdate 的作用,把頁(yè)面上的顯示值也過(guò)濾一遍
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105202.html
摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理源碼版之詳解今天我們來(lái)看看處 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 ...
摘要:首先,兄弟,容我先說(shuō)幾句涉及源碼很多,篇幅很長(zhǎng),我都已經(jīng)分了上下三篇了,依然這么長(zhǎng),但是其實(shí)內(nèi)容都差不多一樣,但是我還是毫無(wú)保留地給你了。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也...
摘要:執(zhí)行的時(shí)候,會(huì)綁定上下文對(duì)象為組件實(shí)例于是中的就能取到組件實(shí)例本身,的代碼塊頂層作用域就綁定為了組件實(shí)例于是內(nèi)部變量的訪問(wèn),就會(huì)首先訪問(wèn)到組件實(shí)例上。其中的獲取,就會(huì)先從組件實(shí)例上獲取,相當(dāng)于。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得...
摘要:當(dāng)東西發(fā)售時(shí),就會(huì)打你的電話通知你,讓你來(lái)領(lǐng)取完成更新。其中涉及的幾個(gè)步驟,按上面的例子來(lái)轉(zhuǎn)化一下你買東西,就是你要使用數(shù)據(jù)你把電話給老板,電話就是你的,用于通知老板記下電話在電話本,就是把保存在中。剩下的步驟屬于依賴更新 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【...
摘要:我們都知道分為普通和作用域,兩個(gè)內(nèi)容都很多,所以分兩部分進(jìn)行講述。今天講的是普通其實(shí)普通,表示默認(rèn)和具名,只是他們的處理方式都差不多,就只是是否有自定義名字而已,所以,表示一種類型。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)...
閱讀 3979·2021-11-16 11:44
閱讀 5231·2021-10-09 09:54
閱讀 2039·2019-08-30 15:44
閱讀 1691·2019-08-29 17:22
閱讀 2763·2019-08-29 14:11
閱讀 3401·2019-08-26 13:25
閱讀 2332·2019-08-26 11:55
閱讀 1603·2019-08-26 10:37