资讯专栏INFORMATION COLUMN

【Vue原理】VModel - 白话版

keke / 780人阅读

摘要:执行的时候,会绑定上下文对象为组件实例于是中的就能取到组件实例本身,的代码块顶层作用域就绑定为了组件实例于是内部变量的访问,就会首先访问到组件实例上。其中的获取,就会先从组件实例上获取,相当于。

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

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

【Vue原理】VModel - 白话版

说到 Vue,感觉第一印象就是双向绑定,所以v-model键值是Vue印象的半壁江山啊,这么重要的东西,你好歹要知道是怎么实现的吧

我们今天就来讲解双向绑定的工作原理,你应该知道,双向绑定就是通过绑定 dom 事件来实现的,可是,怎么绑定的事件,绑定什么事件?

首先,双向绑定,我个人认为应该分为 初始化绑定 和 双向更新 两part。

初始化绑定,就是初始化时给表单元素绑定值,绑定事件,为双向更新做准备

双向更新,就是任意一边变化,同时能让另一个边更新

双向更新那是后话,只有一开始时成功执行绑定操作才会有之后 双向更新这个东西,所以,今天按顺序来了解两个part,从四个问题开始

1、v-model 怎么给表单绑定数据

2、v-model 绑定什么事件

3、v-model 怎么绑定事件

4、v-model 如何进行双向更新

TIP

v-model 还可以用在 自定义组件上,但是很明显,这次我们先不讲这一块,而是先将正常的表单使用

先看结论

我们先以 input text 类型讲解,对于其他的表单元素,流程都差不多,只是中间涉及的内容不同。所以就先讲个例子,然后具体在源码版全部一起说

1、怎么赋值?v-model 绑定的数据赋值给表单元素的 value 属性

2、怎么绑定事件?解析不同表单元素,配置相应的事件名和事件回调,在插入dom之前,addEventListener 绑定上事件

3、怎么双绑?外部变化,触发事件回调,event.target.value 赋值给model绑定的数据;内部变化,修改表单元素属性 value

看完结论,有点懵?我们来看看具体的内容,结果导向来进行学习

下面的讲解以下面这个为例

v-model 怎么给表单绑定数据

获取值流程

首先,上面例子解析后的渲染函数是下面这样(已简化,只保留表单值相关)

(function(){    
    with(this){  
        return _c("div",[
            _c("input",
                domProps:{"value":name}
            )
        ])
    }
})

1、这个渲染函数是没有执行的 匿名函数。执行的时候,会绑定上下文对象为 组件实例

2、于是 with(this) 中的 this 就能取到 组件实例本身,with 的代码块 顶层作用域 就绑定为了 组件实例

3、于是 with 内部变量的访问,就会首先访问到 组件实例上。其中 name 的 获取,就会先从 组件实例上获取,相当于 vm.name。赋值完成后,domProps 就是下面这样

{ domProps:{value:111} }

4、上面的 value 是 v-model 解析成的原生属性,保存在属于该节点 input 的 domProps 对象存储器中

绑定值流程

创建dom input 之后,插入dom input 之前,遍历该 input 的 domProps ,逐个添加给 input dom

简化后的代码像下面这样进行赋值

for(var i in domProps){
    input[i]=domProps[i]
}

其中给节点赋值就是这样

input.value = 111
v-model 绑定什么事件

不同的表单元素使用v-model,会绑定不同的 事件

change 事件

select,checkbox,radio

input 事件

这是默认事件,当不是上面三种表单元素时,会解析成 input 事件

比如 text、number 等 input 元素和 textarea

TIP

实际上关于 input 和 textarea 绑定的事件远不止 input 一个事件,但是涉及内容太多,打算放在源码版说明,这里先简单默认是 input 事件

v-model 怎么绑定事件

上面例子解析成下面的渲染函数(已简化,只保留事件相关)

with(this) {    
    return _c("div", [
        _c("input", {        
            on: {            
              "input": function($event) {
                  name = $event.target.value
              }
            }
        }
    )])
}

解析事件流程

1解析不同表单元素,配置不同的事件

2拼装 事件回调函数,不同表单元素,回调不一样

3把 事件名和拼装回调 配套 保存给相应的表单元素的 on 事件存储器

什么时候绑定事件

生成 input dom 之后,插入input dom 之前

怎么绑

使用之前保存的 事件名和 事件回调,给 input dom 像下面这样绑定上事件

input.addEventListener("input",function($event) {    
    name = $event.target.value 
})
v-model 如何进行双向更新

双向,指的是 外部和内部

外部变化:用户手动改变表单值,输入或者选择

内部变化:从内部修改绑定值

内部变化

1、v-model 绑定了 name ,name 会收集到 本组件的 watcher

a. 下面渲染函数执行时,会绑定本身组件实例为上下文对象

b. name 访问的是 组件实例的 name

c. name 此时便收集到了 当前正在渲染的组件实例,当前渲染的实例是自己,于是收集到了自身的 watcher

(function(){    
  with(this){  
    return _c("div",[_c("input",
        domProps:{"value":(name)})
    ])
  }
})

如果你不懂 收集 watcher 什么意思,建议看下我的另一篇文章

【Vue原理】响应式原理 - 白话版

2、内部修改 name 变化,通知收集器内的 watcher 更新,所以本组件会更新,上面的渲染函数重新执行,便 重新从实例读取 name

3、重新给 input dom 的 value 赋值,于是 页面就更新了

怎么赋值?那是回到第一个问题了,兄弟

外部变化

手动改变表单,事件触发,执行事件回调(下面这个),更新组件数据 name

function($event) {    
    name = $event.target.value 
}

更新内部数据流程

1、当事件触发的时候,会把 表单的值 赋值给 name

2、name 是从 组件实例上访问的

3、所以这次赋值会 直接改变组件实例的 name

回调怎么赋值给组件实例的name

一开始不懂,所以不理解,也没查到,写了个例子,大概理解了意思

1、因为事件回调 在 with 里面声明

2、于是事件回调的 作用域链最顶层 就加上了一层 with 绑定的作用域

3、就算事件回调不在 with 中执行,事件回调中的 变量访问,也会先访问之前 with 绑定过的作用域,因为作用域链的最顶层

with举栗子

var name=22
var a={name:"a"}
with(a){    
    var fn=function(){        
        console.log(name)
    }
}
fn()

你认为 fn 执行的时候,会打印出什么呢?行了,给你看结果了

好吧,再一次深刻认识到一个知识点,with 绑定作用域原来这么强,离开with执行,还是先访问他的作用域,脱离不出魔爪啊,强盗作用域

回来总结

于是当事件回调执行的时候,会 直接赋值 给 组件实例的name,这样便通过外部改变了内部数据

TIP

外部变化,本来可能会存在一种情况

a、手动修改表单后, 回调内会更新组件的值

b、组件的值更新之后,会通知组件更新,组件更新时,便又会重新把input 赋值一遍

非常多余的一步操作,所以这里,Vue做一个判断,判断旧值和 新值是否相等,不等才更新,关于旧值,会保存在 dom 的 _value 属性

总结

v-model 三要素

1、绑定属性

2、绑定事件

3、属性+事件组合完成双向更新

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105204.html

相关文章

  • Vue原理VModel - 源码 之 select 详解

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理源码版之详解今天我们来看看处 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 ...

    lsxiao 评论0 收藏0
  • Vue原理VModel - 源码之input详解

    摘要:因为失去焦点之后被强制更新了一波嗯,这就是的作用,把页面上的显示值也过滤一遍 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】VModel - 源码版之input详...

    leanxi 评论0 收藏0
  • Vue原理VModel - 源码 之 表单元素绑定流程

    摘要:首先,兄弟,容我先说几句涉及源码很多,篇幅很长,我都已经分了上下三篇了,依然这么长,但是其实内容都差不多一样,但是我还是毫无保留地给你了。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也...

    sarva 评论0 收藏0
  • Vue原理】Compile - 源码 之 generate 节点数据拼接

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理源码版之节点数据拼接上一篇我们 写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究...

    fizz 评论0 收藏0
  • Vue原理】响应式原理 - 白话

    摘要:所以我今后打算把每一个内容分成白话版和源码版。有什么错误的地方,感谢大家能够指出响应式系统我们都知道,只要在实例中声明过的数据,那么这个数据就是响应式的。什么是响应式,也即是说,数据发生改变的时候,视图会重新渲染,匹配更新为最新的值。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 V...

    gggggggbong 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<