zoukankan      html  css  js  c++  java
  • [Vue源码分析] v-model实现原理

    前言:
    我们都知道使用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.name为model,对应的state.directives[dir.name]相当于state.directives[model],directives的定义位于src/platforms/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上。
    即,以下两份代码其实是一个意思。
    第一份:

    第二份

    ————————————————
    版权声明:本文为CSDN博主「ECMAScripter」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/fabulous1111/article/details/85265503

  • 相关阅读:
    我的浏览器收藏夹分类
    我的浏览器收藏夹分类
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
  • 原文地址:https://www.cnblogs.com/yzhihao/p/11469344.html
Copyright © 2011-2022 走看看