[Vue源码分析] v-model实现原理

最近小组有个关于vue源码分析的分享会,提前准备一下…

前言:
我们都知道使用v-model可以实现数据的双向绑定,及实现数据的变化驱动dom的更新,dom的更新影响数据的变化。那么v-model是怎么实现这一原理的呢?接下来探索一下这部分的源码。

前期准备
①:vue2.5.2源码(用于阅读、查看关联等)
②:建立vue demo,创建包含v-model指令的实例(用于debugger)
以下为demo:

genDirectives
在模板的编译阶段, v-model跟其他指令一样,会被解析到 el.directives 中,之后会通过genDirectives方法处理这些指令,genDirectives方法位于src/compiler/codegen/index.js中:

我们去到之前建立的demo,找到demo中node_modules/vue/dist/vue.esm.js下的genDirectives方法,打上debugger,如图:

可以看到传进来的el是ast语法树,el.directives是el上的指令,如下:

回到genDirectives源码,循环指令时都执行了const gen: DirectiveFunction = state.directives[dir.name]这个方法,state.directives是什么?
当遍历到v-model的时候,dir.www.ysyl157.com   name为model,对应的state.directives[dir.name]相当于state.www.gouyiflb.cn  directives[model],directives的定义位于src/platforms www.dasheng178.com /web/compiler/directives/index.js 中:

本次分析的v-model,对应的也就是model方法,也就是其实!!gen(el, dir, state.warn)执行的是model方法,!!用于将返回值转为Boolean类型,model的定义位于index同目录下。

model

model方法根据传入的参数对tag的类型进行判断,调用不同的处理逻辑,本demo中tag的类型为input,所以会执行genDefaultModel方法,为了节约时间,就不去源码中找了,藏得比较深,直接在demo引用的单文件源码vue.esm.js中搜索genDefaultModel。

genDefaultModel
发现定义如下,打上debugger,以便调试:

通过控制台查看变量信息,可以看到:

可以看到里边的genAssignmentCode(value, valueExpression)在此demo中相当于genAssignmentCode("msg", ""$event.target.value""),执行此方法后返回的是一个字符串:msg=$event.target.value,后来命中了needCompositionGuard,所以code变成了if($event.target.composing)return;msg=$event.target.value,if($event.target.composing)return;的作用是不记录用户未确定的输入,比如:

注释掉if(needCompositionGuard)的话用户没确定的也会展示,如图:

随后会依次执行以下两个方法:

addProp
先注释掉addHandler,避免对研究此方法产生影响。

可以看到此方法的功能为给el添加props,首先判断el上有没有props,如果没有的话创建props并赋值为一个空数组,随后拼接对象并推到props中,代码在此demo中相当于push了{name: "value", value: "(msg)"},打印一下这番操作后的el,可以看到添加了props的el的结构如下:

这个方法其实是在input上动态绑定了value,此时,原本的<input v-model="msg">相当于变成了<input v-bind:value="msg">,随后继续执行addHandler。

addHandler
以下仅包含关键代码,打上debugger以便查看数据。

控制台查看el的debuuger结果:

可以看到比执行addHandler之前,el上多了events,可以得知这个方法主要给el 添加了事件处理,在此demo中的话相当于在 input 上绑定了 input 事件。

总结:
也就是说,到此为止,原本的<input v-model="msg">相当于变成了<input v-bind:value="msg" v-on:input="msg=$event.target.value">,当用户输入的使用触发msg=$event.target.value进而更新msg,msg通过v-bind绑定到输入框的value上。
即,以下两份代码其实是一个意思。
第一份:

第二份

原文地址:https://www.cnblogs.com/qwangxiao/p/10193657.html

时间: 2024-10-30 22:30:17

[Vue源码分析] v-model实现原理的相关文章

【MyBatis源码分析】插件实现原理

MyBatis插件原理----从<plugins>解析开始 本文分析一下MyBatis的插件实现原理,在此之前,如果对MyBatis插件不是很熟悉的朋友,可参看此文MyBatis7:MyBatis插件及示例----打印每条SQL语句及其执行时间,本文我以一个例子说明了MyBatis插件是什么以及如何实现.由于MyBatis的插件已经深入到了MyBatis底层代码,因此要更好地使用插件,必须对插件实现原理及MyBatis底层代码有所熟悉才行,本文分析一下MyBatis的插件实现原理. 首先,我们

vue源码分析:响应式之依赖收集

今天记录下vue源码的响应式的源码学习,第一步,我们想下,为什么为们写一个data.然后里边的数据变化就能映射到dom的变化上.这里用到了Object.defineProperty(obj,key, {}),如果你还不了解建议去jsmdn上仔细了解下,这个函数的目的就是检测你得赋值和取值的过程用来定义自己的行为,比如obj[key]会拿到配置里边的get函数定义,obj[key] = 'xxx'会调用配置中的set.那么vue也是一样的,在get中做了依赖收集(也就是说哪些dom用到了我定义的这

vue 源码分析之如何实现 observer 和 watcher

https://segmentfault.com/a/1190000004384515 本文能帮你做什么? ..好奇vue双向绑定的同学, 可以部分缓解好奇心 还可以帮你了解如何实现$watch 前情回顾 我之前写了一篇没什么干货的文章..并且刨了一个大坑.. 今天..打算来填一天..并再刨一个..哈哈 不过话说说回来了.看本文之前,, 如果不知道Object.defineProperty,还必须看看解析神奇的 Object.defineProperty 不得不感慨vue的作者,人长得帅,码写的

内核通信之Netlink源码分析-用户内核通信原理3

2017-07-06 上节主讲了用户层通过netlink和内核交互的详细过程,本节分析下用户层接收数据的过程-- 有了之前基础知识的介绍,用户层接收数据只涉及到一个核心调用readmsg(), 其他的就不多介绍了,不太明白的请参考之前的文章,我们还是重点看下内核究竟在背后做了什么!该函数在内核对应于read_msg系统调用 SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags) { i

通过ThreadPoolExecutor源码分析线程池实现原理

为什么要用线程池 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性.使用线程池可以重复利用已创建的线程降低线程创建和销毁带来的消耗,随之即可提高响应速度(当一个任务到达时,不需要重新创建线程来为之服务,重用已有线程),还可以通过线程池控制线程资源统一分配和监控等. 线程池工厂Executors JDK 提供了创建线程池的工厂类 Executors,该类提供了创建线程池的静态方法: public static ExecutorService newFixedThreadP

Vue源码分析(二) : Vue实例挂载

author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-with-compiler.js & src/platforms/web/runtime/index.js 等文件中都有对Vue.prototype.$mount的定义: // vue/platforms/web/entry-runtime-with-compiler.js Vue.prototype.$mount = function ( e

vue源码分析

双向数据绑定 1. js的eventloop micro 微队列,promise的then,async await,observer, 优先级高于宏队列.window.MutationObserver属于observer macro 宏队列,setTimeout,setInterval, click,event事件,ajax, var MutationObserver = window.MutationObserver; var target = document.querySelector('

十二)CodeIgniter源码分析之Model.php

1 <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 2 /** 3 * CodeIgniter Model Class 4 */ 5 class CI_Model { 6 7 /** 8 * Constructor 9 */ 10 function __construct() 11 { 12 log_message('debug', "Model Class Initialized&quo

vue源码分析之目录架构(一)

compiler compiler 目录包含 Vue.js 所有编译相关的代码.它包括把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能 core core 目录包含了 Vue.js 的核心代码,包括内置组件.全局 API 封装,Vue 实例化.观察者.虚拟 DOM.工具函数等等. platform Vue.js 是一个跨平台的 MVVM 框架,它可以跑在 web 上,也可以配合 weex 跑在 native 客户端上.platform 是 Vue.js 的入口,2 个目录代表 2