![0c4575d9c732cdab87aaacf8e77ce9d7.png](https://i-blog.csdnimg.cn/blog_migrate/ac1ad576b44e6289ae08dbdaa35a15d7.jpeg)
专注 Vue 源码分享,为了方便大家理解,分为了白话版和 源码版,白话版可以轻松理解工作原理和设计思想,源码版可以更清楚内部操作和 Vue的美,喜欢我就关注我的公众号,公众号的文章,排版更好看
如果你觉得排版难看,请点击下面链接 或者 关注公众号
【Vue原理】VModel - 源码版 之 表单元素绑定流程mp.weixin.qq.com![9c33bf7f8dcd931c1a9e71ca6724ab3f.png](https://i-blog.csdnimg.cn/blog_migrate/396f00119dfb3875c2b9fd96b2e9c59d.jpeg)
![1e66c406c6921d2170fdbfef4da96599.png](https://i-blog.csdnimg.cn/blog_migrate/31f52e9b6cf75265ae38918c66476b53.jpeg)
今天讲解 v-model 的源码版。首先,兄弟,容我先说几句
![abbfd6ab8c3501d2a371c50423b70fab.png](https://i-blog.csdnimg.cn/blog_migrate/d69a5a8b062a9d86c32d40088d98b82a.jpeg)
v-model 涉及源码很多,篇幅很长,我都已经分了上下 三篇了,依然这么长,但是其实内容都差不多一样,但是我还是毫无保留地给你了。你知道我这篇文章写了多久,一个多星期啊,不是研究多久啊,是写啊写啊,不停地修修改改,一直在想如何才能讲明白
![611b9f70ff01507f6efdaec181176c0c.png](https://i-blog.csdnimg.cn/blog_migrate/4e079c476d54777f2a846882eab3001f.jpeg)
如果你做好了十足的学习准备,会对你事半功倍,如果你只是看看,请看白话版吧,不然估计会越看越烦.....
如果你看过白话版,估计你会了解今天内容的大概,也能很快就入戏
今天讲解不同表单元素的Vue是如何处理的,表单元素有
input、textarea、select、checkbox、radio 五大种
所以,我们把每个表单元素当做一个模块,然后每个模块解决三个问题的流程,来开始我们今天的表演
1、v-model 如何绑定表单值
2、v-model 如何绑定事件
4、v-model 如何双向更新
TIP
下面所有涉及到的源码,为了方便理解,都是简化过的,因为源码太长,所以只保留主要思想,去掉了很多兼容处理以及错误处理
![8c66dc5fdac4c7b0c574d1ffc465ef50.png](https://i-blog.csdnimg.cn/blog_migrate/a84a07840fa0ab1fec11a0179af68fd9.png)
v-model 指令的处理
我们现在假设模板的解析已经到了 解析 v-model 的部分....
Vue 会调用 model 方法 来解析 v-model ,这个方法里面,针对不同的表单元素,再调用不同的专属方法进行深度解析
function
你也看到了,上面每种表单元素都会使用一个方法来特殊照顾,不过这些方法,作用大致一样
1、给表单元素设置绑定值
2、给表单元素设置事件及回调
所以这里,我们把方法的都设计到的方法以及流程说一下
插播上面的el 是什么?
el 是 ast,而我的理解就是解析模板后,用树结构来表示某个dom节点,这里先不用深究,你就只要知道他是保存解析模板后所有的数据,包括你绑定的事件,绑定的指令,绑定的属性等等,一张图看下
![e5814ca7d96f2da107b9bcec7753735e.png](https://i-blog.csdnimg.cn/blog_migrate/7b1da222c74e6c0786ec6c51a960e123.jpeg)
下面所有的处理都是以 el 为基础的
表单元素设置绑定值
什么叫设置绑定值?
首先,比如你给表单元素设置 v-model ="name",name 是 内部数据吧,所以要把 name 和 表单元素 两个紧紧绑定起来,方便后面进行双向更新
这里讲的是每个表单元素绑定值的流程
他们都会调用 addProp 去保存绑定的属性 然后 绑定属性,流程一样,所以提出来讲,但是具体绑定什么属性,每种元素都不尽相同,在下面表单元素模块会详解
1、调用 addProp,把 value 添加进 el.props
function
2、接下来的解析,el.props 会拼接成进字符串 domProps
function
3、在插入 dom 之前,调用 updateDOMProps,把 上面保存的 domProps 遍历赋值到 dom 上
function
表单元素设置事件以及回调
这里讲的是每个表单元素绑定事件的流程
1、拼接事件
每种元素拼接事件都不一样,在下面表单元素模块会详解
2、保存事件名和拼接好的回调
每个元素的 event 事件 和 拼接的回调是不一样,但是他们保存的流程都是一样的,都会调用下面的方法,addHandler 去保存事件
下面 el 是dom 元素,event 是事件名,code 是拼接的回调
![0d9f37618578a6533b0b428a49bbbd40.png](https://i-blog.csdnimg.cn/blog_migrate/ad2abecd98177c13f220bd7f0b373c6d.png)
function
3、完善拼接回调
function
genHandlers遍历 el.event ,每一项的回调最外层包上一层 function 字符串,并把 所有事件 逐个拼接成 on 字符串
function
转接的 初始数据和结果 像下面这样
![01d2344ebd1f748bc0c18475b24ee764.png](https://i-blog.csdnimg.cn/blog_migrate/f33f8370e5e0abd667a1dc590570236e.jpeg)
4、绑定事件
在插入 dom 之前
会调用到 updateDOMListeners,把 上面保存到 on 的 所有事件, 遍历绑定到 dom 上
updateDOMListeners 其实兜兜转转了很多方法 来处理,为了方便理解,已经非常简化,但是意思是不变的
尤大:卧槽,我写几百行,你浓缩成5行,你这是要向全国人民谢罪的啊
![05b43725dc61ac0e6c36f8c11a37764f.png](https://i-blog.csdnimg.cn/blog_migrate/e94f404a1c462dcdccf0816fbec6e95c.jpeg)
function
下面所有例子使用这个vue实例,所有绑定 v-model 我都用 name
![aec8638dd45cd6eb6c7354ce83b98c45.png](https://i-blog.csdnimg.cn/blog_migrate/c75bc1b4372980c4bd2a3f7d330008e3.jpeg)
![8c66dc5fdac4c7b0c574d1ffc465ef50.png](https://i-blog.csdnimg.cn/blog_migrate/a84a07840fa0ab1fec11a0179af68fd9.png)
Input、Textarea
哟哟,看过 model ,就知道 这两种元素是使用 genDefaultModel 处理的
function
绑定值
看了上面的函数,你就知道啦,input 和 textarea 调用 addProp 绑定的是 value
拼接事件
其实这里精炼就一句话,比 jio 简单
name = $event.target.value
但是呢!input 这里其实是很复杂的,比如兼容 range 啦,预输入延迟更新啦 等等,但是现在我们不说这些,放到下篇来讲
然后,你能看到,input 和 textarea 一般绑定的是 input 事件,但是也有其他的处理,下篇讲啦
编译后的渲染 render 函数
![6136eb6474de8438ddcf8dfc45ba7318.png](https://i-blog.csdnimg.cn/blog_migrate/3f0c18d13786ba4a3a90124ad1000d3d.png)
with
双向更新
我们可以看到上面的 render 执行的时候,从实例读取了 name,name 收集到 本组件 watcher
1、内部变化,通知更新 watcher,render 重新执行,获取新的 name,绑定到 dom 元素属性 value
2、外部变化,看上面的回调事件,可以知道直接把 $event.target.value 赋值给 内部值name
![8c66dc5fdac4c7b0c574d1ffc465ef50.png](https://i-blog.csdnimg.cn/blog_migrate/a84a07840fa0ab1fec11a0179af68fd9.png)
Select
来看看 处理 select 的 genSelect 方法
function
绑定值
select 元素绑定的属性是 selectedIndex,但是 select 并没有在 genSelect 方法中调用addProp 绑定某个属性
那么 select 在哪里设置了呢?Vue 专门使用了方法 setSelected 设置 selectedIndex,这个方法现在不说,你只要知道,他是更新 selectedIndex 的就好了,后面会有一篇专门说
疑惑为什么 select 不像 input 一样直接绑定 value,这样,不是也可以确定选项吗?
按我的理解呢,我觉得应该是原始select的 value 只有字符串一类型的值,而 Vue 的select 支持 数字和字符串两种类型的值啊
拼接事件
观察下面的渲染函数,就可以很清楚地名表,select 的回调是怎么一回事了
1、从所有option 中 筛选出被选择的option
2、使用数组保存所有筛选后的option的value
3、判断是否多选,多选返回数组,单选返回数组第一项
然后,你还能知道 select 绑定的是 change 事件
献上 select 的渲染 render 函数
![99f84879fd06876276659fdcbf44c666.png](https://i-blog.csdnimg.cn/blog_migrate/e3c3f5341ed78f7f6456eed952a394bd.png)
with
双向更新
render 执行时,directive 处从实例读取了 name, name 收集到 本组件 watcher
1、内部变化,通知更新 watcher,上面 render 重新执行,获取新name,于是更新 select 元素属性 selectedIndex,于是select 当前选项就改变了
2、外部变化,直接赋值给 绑定值,绑定值变化,通知 watcher 更新,更新完,重新设置 selectedIndex
![8c66dc5fdac4c7b0c574d1ffc465ef50.png](https://i-blog.csdnimg.cn/blog_migrate/a84a07840fa0ab1fec11a0179af68fd9.png)
Checkbox
genCheckboxModel 源码奉上
function
绑定值
赋值给 checked
看上面的方法就知道啦,调用 addProps,设置 checked 值
拼接事件
哈哈,还是看下面的渲染函数,看下 checkbox 的回调,其实意思就是
1、数组,分是否选择
a. 选择,把当前选项 concat 进数组
b. 取消选择,把当前选项 移除出数组
2、非数组,直接赋值
你还能知道 checkbox 绑定的是 change 事件
来看看checkbox 的渲染render函数
![2478a847808224d34c1e817c7437121a.png](https://i-blog.csdnimg.cn/blog_migrate/242ad4523dfabc5bd9fb73496149feaf.png)
with
双向更新
在 render 执行的时候,从实例读取了 name,name 收集到 本组件的 watcher
1、内部变化,通知更新 watcher,上面的 render 重新执行,获取新的 name,更新 checkbox 元素属性 checked
2、外部变化,判断是否多选和是否选择,来决定如何赋值 更新 绑定值 name
![8c66dc5fdac4c7b0c574d1ffc465ef50.png](https://i-blog.csdnimg.cn/blog_migrate/a84a07840fa0ab1fec11a0179af68fd9.png)
Radio
处理 radio 元素的 genRadioModel 源码
function
怎么赋值
直接赋值给 checked,你看上面的方法调用 addProp 可以看到
拼接事件
这个真的更加简单了...比 input 还简单啊,都不用获取值,只是直接赋值为 radio 的值
name="1", 1 是你设置给 radio 的value值
你还能知道 radio 绑定的是 change 事件
看下下面的radio 的渲染函数你就懂了
![82ecf7b35ce4339580f29789e5121177.png](https://i-blog.csdnimg.cn/blog_migrate/79093ff0db6744809921568caf877a58.png)
with
双向更新
在 render 执行的时候,绑定值 收集到 本组件的 watcher
1、内部变化,通知更新 watcher,render 重新执行,获取新的 name,更新 radio 元素属性 checked
2、外部变化,直接赋值 更新 绑定值 name 等于 radio元素属性 value
![8c66dc5fdac4c7b0c574d1ffc465ef50.png](https://i-blog.csdnimg.cn/blog_migrate/a84a07840fa0ab1fec11a0179af68fd9.png)
历史分享
【Vue原理】Vue源码阅读总结大会 - 序
【Vue原理】学会调试Vue源码
【Vue原理】响应式原理 - 白话版
【Vue原理】Props - 白话版
【Vue原理】月老Computed - 白话版
【Vue原理】Watch - 白话版
【Vue原理】Mixin - 白话版
【Vue原理】Methods - 源码版
![8c66dc5fdac4c7b0c574d1ffc465ef50.png](https://i-blog.csdnimg.cn/blog_migrate/a84a07840fa0ab1fec11a0179af68fd9.png)
最后
希望你认真阅读后,能豁然开朗。如果你懂了,我的目的也达到了,如果你还不懂,可以留言告诉我哦,百分百回复好吧
如果你能转发一下,就更好啦,技术人交流 只用文章
![1e66c406c6921d2170fdbfef4da96599.png](https://i-blog.csdnimg.cn/blog_migrate/31f52e9b6cf75265ae38918c66476b53.jpeg)