【Vue原理】VModel - 源碼版 之 select 詳解

寫文章不容易,點個讚唄兄弟
專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧
研究基於 Vue版本 【2.5.17】

若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧node

【Vue原理】VModel - 源碼版 之 select 詳解 數組

今天咱們來看看 v-model 處理 select 有什麼特殊的地方dom

前面已經有三篇說明VModel了函數

【Vue原理】VModel - 白話版 學習

【Vue原理】VModel - 源碼版 之 表單元素綁定流程 spa

【Vue原理】VModel - 源碼版之input詳解 3d

經過第一篇源碼分享,咱們就知道 Vue是經過 設置 select 的 selectedIndex 來控制選項的,code

哈哈,如今咱們就是來分析究竟是怎麼設置 selectedIndex 的component

好的,咱們必定要帶着問題進行學習,這樣學完纔有用blog

一、Vue 如何設置 selectedIndex

二、Vue 在哪裏設置 selectedIndex

Vue 如何設置 selectedIndex

Vue 是經過 一個 setSelected 的方法專門來設置 selectedIndex 的,咱們來看下源碼

function setSelected(el, binding, vm) {   

    var selected, option;   
 
    for (var i = 0, l = el.options.length; i < l; i++) {
        option = el.options[i];   
        if (isMultiple) {
            selected = value.indexOf(option) > -1;  
            if (option.selected !== selected) {
                option.selected = selected;
            }
        } 

        else {            
            if (option.value == value) {                
                if (el.selectedIndex !== i) {
                    el.selectedIndex = i;
                }               
                return
            }
        }
    } 
   
    if (!isMultiple) {
        el.selectedIndex = -1;
    }

}

兩處會修改 selectedIndex 的地方我已經加紅加粗

簡單解釋下 setSelected 的做用

一、綁定值沒法匹配任何option 時,設置 selectedIndex =-1,而後select 就會顯示空

舉栗子

image

image

select 的 selectedIndex 是-1,而後選擇框內顯示空

image

image

二、選擇時,若是多個options 值相等時,只取第一個相等項

舉栗子
三個選項的 value 都同樣

image

image

image

哈哈,我明明選了3,可是 顯示1,這就是 Vue 作的處理,多個相同值的選擇,只去第一個

可是這個也是有條件的,必須在 value 變化的時候,纔會進行更新,因而纔會有 判斷操做

好比如今select 的value是 1,你再選擇一個 也是 1 的其餘選項,Vue 就不會更新,也就不會判斷,你選了就選了,無論你了

看圖,初始化 select value 爲空,而後選擇 value 是1 的 第三個選項,

哦豁,忽然變成第一個選項了

而我再選擇 3 和 2 的時候,卻不會變成 第一個選項,所以 3 和2 的 value 都是 1,value 沒有變化,select 不會更新

image

三、選擇後,options 變化,會根據以前的選擇,更新它在options的位置

image

image

image

options 改變了,而後把 1 的位置變成最後一個,而後 Vue 就會相應地把 selectedIndex 的位置更新爲 新options 中對應的位置

image


在哪裏設置 selectedIndex

Vue 會在 v-model 的兩個鉤子函數中更新 select 的 selectedIndex

inserted

當dom被插入到頁面中後,會觸發這個鉤子函數

上一篇詳解input咱們已經能知道,inserted 會處理select

看下 inserted 源碼(只有select 處理部分)

function inserted(el, binding, vnode, oldVnode) {    

    if (vnode.tag === 'select') {

        // 設置 select 的selectedIndex 初始值
        setSelected(el, binding, vnode.context);

        // 把options 的value,全都保存到一個數組
        el._vOptions = 
            [].map
            .call(el.options, function(o){
                return o.value
            });
    }
}

componentUpdated

當組件更新完畢以後,觸發 這個鉤子

這個鉤子函數只針對 select 處理

上 componentUpdated 鉤子函數源碼

function componentUpdated(el, binding, vnode) {    

    if (vnode.tag === 'select') {

        setSelected(el, binding, vnode.context);     

        // 這是以前保存的 舊 的 options 的 全部 value 的數組 好比[ 1,2,3]
        var prevOptions = el._vOptions;   

        // 拿到 如今全部 option 的value 存到數組
        var curOptions = el._vOptions = [].map.call(el.options, getValue);   

        // 當 options 變化,並且跟舊option 每一個都不同
        if (curOptions.some(function(o, i) {            
            return ! (o==prevOptions[i])
        })) {  

            var needReset = el.multiple ? 

            binding.value.some(function(v) {       
                 return hasNoMatchingOption(v, curOptions);
            }) :   

            // 綁定值變化了,並且綁定值 匹配不到 options
            // hasNoMatchingOption 是匹配 某個值是否在數組中 
            binding.value !== binding.oldValue 
            && hasNoMatchingOption(binding.value, curOptions);  

            if (needReset) {
                trigger(el, 'change');
            }
        }
    }

看源碼,這個鉤子大概作了兩件事

一、當即更新 selectedIndex

爲何要當即更新,怕 options 改變了,而 select.selectedIndex 沒有變,致使對應上了 新options 的 index 項,上錯花轎嫁對郎

[ 1,2,3 ] 選擇了第3項, 而後 index=2,值是3

而後 options 數據改變了,變成了 [7,8,9],而 index 仍是2,而顯示值 變成了 9

很明顯這不符合邏輯啊,必須每次組件更新都要更新selectedIndex

image

二、更新綁定值

上面 componentUpdated 能夠看到會手動觸發 change 回調

觸發的條件是

一、options 改變,並且跟舊options每一個都不同

二、綁定值也改變

三、新綁定值沒法在 新options 中匹配對應值

我也不懂爲何要調用一次 select 的 change 回調

要不咱們 一塊兒來查一下這個起因吧

首先,change 回調,做用是更新綁定值,難道就是爲了更新?

咱們寫個例子看一下

image

image

兩秒以後,會把 綁定值 和 options 同時改變,並且name並不存在arr 中

image

既然 一開始認爲做用更新 綁定值,那咱們看下綁定值更新成了什麼鬼

image

變成了 undefined

的確是更新了綁定值哦,但是爲何要更新綁定值爲 undefined 呢?想不通.....

上面是從內部去修改 綁定值的,咱們從外部修改看一下,把內部修改的語句註釋掉

image

image

發現 外部修改綁定值,再改變 options ,外部修改的綁定值是不會隨着options變化而更新的哦

話說其實這裏我沒太想通,也不知道本身想得對不對,感受這裏能夠討論一下

根據上面的現象,我說出個人想法

我以爲尤大的想法是,從用戶角度出發

若是用戶沒有選擇任何option

可是 options 和 綁定值 同時改變,並且綁定值還不匹配options

這個綁定值改變有個毛用啊???

做爲表單數據,你本身內部修改綁定值還不匹配任何option

這樣,用戶根本不知道你修改,他壓根沒選擇,而提交的時候,提交卻有數據,這是幹毛?

舉栗子

選擇最愛的水果,options = [ 西瓜,香蕉,番茄 ]

你修改爲了 options = [ 橙子,蘋果,雪梨 ],還把用戶的選擇值改爲 錘子

用戶還不知道你修改了,我喜歡個錘子喜歡

沒道理啊是否是,因此最好是 重置爲 undefined

也恰好符合 源碼的語義 needReset

image

額,我是這麼想的,也不知道對不對,勿噴我,不過我以爲個人想法頗有道理啊

若是用戶已經選擇option

就算options 改變了,那本質上也是沒有錯的,由於是用戶本身選擇,就算不匹配新options,因此就不必重置了

公衆號

相關文章
相關標籤/搜索