【Vue原理】VModel - 源码版 之 select 详解

栏目: JavaScript · 发布时间: 6年前

内容简介:写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本如果你觉得排版难看,请点击

写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 【2.5.17】

如果你觉得排版难看,请点击 下面链接 或者 拉到 下面 关注公众号 也可以吧

【Vue原理】VModel - 源码版 之 select 详解

今天我们来看看 v-model 处理 select 有什么特殊的地方

前面已经有三篇说明VModel了

【Vue原理】VModel - 白话版

【Vue原理】VModel - 源码版 之 表单元素绑定流程

【Vue原理】VModel - 源码版之input详解

通过第一篇源码分享,我们就知道 Vue是通过 设置 select 的 selectedIndex 来控制选项的,

哈哈,现在我们就是来分析到底是怎么设置 selectedIndex 的

好的,我们一定要带着问题进行学习,这样学完才有用

1、Vue 如何设置 selectedIndex

2、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 的作用

1、绑定值无法匹配任何option 时,设置 selectedIndex =-1,然后select 就会显示空

举栗子

【Vue原理】VModel - 源码版 之 select 详解
【Vue原理】VModel - 源码版 之 select 详解

select 的 selectedIndex 是-1,然后选择框内显示空

【Vue原理】VModel - 源码版 之 select 详解
【Vue原理】VModel - 源码版 之 select 详解

2、选择时,如果多个options 值相等时,只取第一个相等项

举栗子 三个选项的 value 都一样

【Vue原理】VModel - 源码版 之 select 详解
【Vue原理】VModel - 源码版 之 select 详解
【Vue原理】VModel - 源码版 之 select 详解

哈哈,我明明选了3,但是 显示1,这就是 Vue 做的处理,多个相同值的选择,只去第一个

但是这个也是有条件的,必须在 value 变化的时候,才会进行更新,于是才会有 判断操作

比如现在select 的value是 1,你再选择一个 也是 1 的其他选项,Vue 就不会更新,也就不会判断,你选了就选了,不管你了

看图,初始化 select value 为空,然后选择 value 是1 的 第三个选项,

哦豁,突然变成第一个选项了

而我再选择 3 和 2 的时候,却不会变成 第一个选项,因此 3 和2 的 value 都是 1,value 没有变化,select 不会更新

【Vue原理】VModel - 源码版 之 select 详解

3、选择后,options 变化,会根据之前的选择,更新它在options的位置

【Vue原理】VModel - 源码版 之 select 详解
【Vue原理】VModel - 源码版 之 select 详解
【Vue原理】VModel - 源码版 之 select 详解

options 改变了,然后把 1 的位置变成最后一个,然后 Vue 就会相应地把 selectedIndex 的位置更新为 新options 中对应的位置

【Vue原理】VModel - 源码版 之 select 详解

在哪里设置 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');
            }
        }
    }
复制代码

看源码,这个钩子大概做了两件事

1、立即更新 selectedIndex

为什么要立即更新,怕 options 改变了,而 select.selectedIndex 没有变,导致对应上了 新options 的 index 项,上错花轿嫁对郎

[ 1,2,3 ] 选择了第3项, 然后 index=2,值是3

然后 options 数据改变了,变成了 [7,8,9],而 index 还是2,而显示值 变成了 9

很明显这不符合逻辑啊,必须每次组件更新都要更新selectedIndex

【Vue原理】VModel - 源码版 之 select 详解

2、更新绑定值

上面 componentUpdated 可以看到会手动触发 change 回调

触发的条件是

1、options 改变,而且跟旧options每个都不一样

2、绑定值也改变

3、新绑定值无法在 新options 中匹配对应值

我也不懂为什么要调用一次 select 的 change 回调

要不我们 一起来查一下这个原由吧

首先,change 回调,作用是更新绑定值,难道就是为了更新?

我们写个例子看一下

【Vue原理】VModel - 源码版 之 select 详解
【Vue原理】VModel - 源码版 之 select 详解

两秒之后,会把 绑定值 和 options 同时改变,而且name并不存在arr 中

【Vue原理】VModel - 源码版 之 select 详解

既然 一开始认为作用更新 绑定值,那我们看下绑定值更新成了什么鬼

【Vue原理】VModel - 源码版 之 select 详解

变成了 undefined

的确是更新了绑定值哦,可是为什么要更新绑定值为 undefined 呢?想不通.....

上面是从内部去修改 绑定值的,我们从外部修改看一下,把内部修改的语句注释掉

【Vue原理】VModel - 源码版 之 select 详解
【Vue原理】VModel - 源码版 之 select 详解

发现 外部修改绑定值,再改变 options ,外部修改的绑定值是不会随着options变化而更新的哦

话说其实这里我没太想通,也不知道自己想得对不对,感觉这里可以讨论一下

根据上面的现象,我说出我的想法

我觉得尤大的想法是,从用户角度出发

如果用户没有选择任何option

但是 options 和 绑定值 同时改变,而且绑定值还不匹配options

这个绑定值改变有个毛用啊???

作为表单数据,你自己内部修改绑定值还不匹配任何option

这样,用户根本不知道你修改,他压根没选择,而提交的时候,提交却有数据,这是干毛?

举栗子

选择最爱的水果,options = [ 西瓜,香蕉,番茄 ]

你修改成了 options = [ 橙子,苹果,雪梨 ],还把用户的选择值改成 锤子

用户还不知道你修改了,我喜欢个锤子喜欢

没道理啊是不是,所以最好是 重置为 undefined

也刚好符合 源码的语义 needReset

【Vue原理】VModel - 源码版 之 select 详解

额,我是这么想的,也不知道对不对,勿喷我,不过我觉得我的想法很有道理啊

如果用户已经选择option

就算options 改变了,那本质上也是没有错的,因为是用户自己选择,就算不匹配新options,所以就没必要重置了

【Vue原理】VModel - 源码版 之 select 详解

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms

Algorithms

Sanjoy Dasgupta、Christos H. Papadimitriou、Umesh Vazirani / McGraw-Hill Education / 2006-10-16 / GBP 30.99

This text, extensively class-tested over a decade at UC Berkeley and UC San Diego, explains the fundamentals of algorithms in a story line that makes the material enjoyable and easy to digest. Emphasi......一起来看看 《Algorithms》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器