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