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

  • 相关阅读:
    秒杀系统核心高性能解决方案(待续)
    LeetCode字符串专题
    LeetCode哈希表专题
    LeetCode排序专题【算法】
    Login项目学习笔记【Android】
    LeetCode树专题(遍历,BST,Trie)(未完成)
    Android studio导入别人项目的艰难记录
    LeetCode树专题(递归)(未完成)
    LeetCode双指针专题【算法】(未完成)
    LeetCode数组与矩阵专题(未完成)
  • 原文地址:https://www.cnblogs.com/yzhihao/p/11469344.html
Copyright © 2011-2022 走看看