未加星标

v-model 使用场景和源码学习

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二04 | 时间 2018 | 作者 红领巾 ] 0人收藏点击收藏
<input v-model="text" type="text"> <input v-model="checkbox" type="checkbox"> data() { return { text: '', checkbox: true } } 复制代码
v-model 使用场景和源码学习

原理:

通过使用v-model指令在元素的输入元素上创建双向数据绑定,它会根据控件类型自动选取正确的方法来更新元素。v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据。 当input输入框值改变/复选框值改变时,text/checkbox值也会同时改变,它负责监听用户的输入事件以更新数据。 radio和checkbox用法当我们选中时,会用之前设定好的值

<input type="radio" v-model="radio" value="radio"> {{radio}} 复制代码 <input v-model="checkbox" type="checkbox" true-value="yes" false-value="no"> {{checkbox}} 复制代码 input事件

对于input,select,textarea原生都有input事件,值更改时,input 事件会同步触发。

methods: { // event是原生dom事件 onValueInput(event) { // srcElement Event.target 属性用来区分元素的 console.log(`${event.srcElement.type}变成了${event.target.value}`) } } 复制代码
v-model 使用场景和源码学习
修饰符

.lazy 取代 input 监听 change 事件因为change事件触发的条件是值改变失去焦点时触发,而input是实时,加上lazy修饰符后等于多了一个失去焦点才能触发的条件。

.number - 输入字符串转为有效的数字如果原值的转换结果为 NaN 则返回原值

注意:

修饰符不能限制输入内容仅仅是把用户输入的内容尝试转换一下 如输入1+1结果为1 它不会去计算只是碰到1是数字,碰到+就停止了 .trim - 输入首尾空格过滤 自定义组件的v-model

父组件中在子组件上使用v-model,默认会用value的prop来接受父组件v-model绑定的值,然后子组件通过input事件将更新后的值传递给父组件

child组件中 <input :value="value" @input="onChildClick($event.target.value)"> props:{ value: { type: String, default: '' } }, methods: { onChildClick(value) { // 需要将更新后的值传递给父组件 this.$emit('input', value) } } 复制代码 父组件中 // 相当于<child :value="name" @input="name = arguments[0]"></child> <child v-model="name"></child> data(){ return{ name:"" } } 复制代码 源码学习

vscode中安装了Search node_modules后查找依赖包中的vue,或者直接去 vue 官网 将项目pull下来。

vue/src/compiler/codegen/index.js中 先看第一个函数,这个书写格式跟我们的习惯不太一样。

function genDirectives (el: ASTElement, state: CodegenState): string | void { // 省略内容 } 复制代码

这种书写方式是flow的语法。首先我们需要了解下什么是flow

flow 它是javascript 静态类型检查工具。 使用的原因:js 是动态类型语言,太灵活容易出现非常隐蔽的隐患代码,在运行阶段各种 bug,类型检查是当前动态类语言的发展趋势。 所谓类型检查,就是在编译期尽早发现(由类型错误引起的)bug,又不影响代码运行(不需要运行时动态检查类型)。 使用场景: 项目越复杂就越需要通过工具的手段来保证项目的维护性和增强代码的可读性。 flow 常用的类型注释语法 借助类型注释来指明期望的类型。类型注释是以冒号 : 开头 // x,y期待类型为number add函数的返回值期待值为number function add(x: number, y: number): number { return x + y } 复制代码 类型注释的使用场景:在函数参数,返回值,变量声明。 class Bar { x: string; // x 是字符串 y: string | number; // y 可以是字符串或者数字 bar(): string { // bar返回值为string return this.foo; } } 复制代码 标记为可选参数 是在定义函数的参数后面加一个 ?,标记为可选参数 function foo(x?) { if (x != undefined) { } } 复制代码 数组类型注释 // 数组类型注释的格式是 Array<T>,T 表示数组中每项的数据类型。在上述代码中,arr 是每项均为数字的数组 var arr: Array<number> = [1, 2, 3] 复制代码 callable对象 callable 对象 (可调用的) 函数也是一个对象,也可以拥有属性,于是函数拥有一个 callable 属性 function makeCallable(): { (x: number): string; foo: number } { function callable(x) { return number.toFixed(2); } callable.foo = 123; return callable; } 复制代码

上面的代码可以拆成两部分看,下面的函数返回一个callable函数,并在返回之前给这个函数添加了foo属性。

function makeCallable() { function callable(x) { return number.toFixed(2); } callable.foo = 123; return callable; } 复制代码

然后分析: { (x: number): string; foo: number }这段,(x:number):string对应的就是callable函数,意思是callable的入参必须是一个number类型,并且返回值是一个string类型。

foo:number对应的就是callable.foo必须为number类型

null和void JavaScript 有 null 和 undefined,Flow 中, null(值) 有 null 类型, undefined 有 void 类型 genDirectives函数 在了解了flow语法后我们继续来看vue源码,打开github上拉下来的项目,examples/commits/index.html <input type="radio" :id="branch" :value="branch" name="branch" v-model="currentBranch"> 复制代码 js部分先从编译阶段分析,首先是 parse 阶段, v-model 被当做普通的指令解析到 el.directives 中,然后在 codegen 阶段定义在 src/compiler/codegen/index.js 中 function genDirectives (el: ASTElement, state: CodegenState): string | void { const dirs = el.directives } 复制代码

有了folw语法的了解,我们知道:之后的是对前面变量的期望类型。但是在编译过程是el和state到底是什么呢?


v-model 使用场景和源码学习
v-model 使用场景和源码学习

可以看到el.directives是一个数组,它的子项包括(arg: null modifiers: undefined name: "model" rawName: "v-model" value: "currentBranch")

state.directives是一个对象,他的子项都是函数包括( bind: (e,t) cloak: O(e,t,n) html: (e,t) model: (e,t,n) on: (e,t) text: (e,t))这些函数 了解了这些参数是什么,继续看下面的代码

function genDirectives (el: ASTElement, state: CodegenState): string | void { const dirs = el.directives // 判断有无指令 if (!dirs) return let hasRuntime = false let i, l, dir, needRuntime // dirs.length表示指令的个数,这里就是将指令都遍历 for (i = 0, l = dirs.length; i < l; i++) { dir = dirs[i] needRuntime = true // 例如我们上面提到的model指令,在此将指令名字对应的函数赋值给gen变量,前面提到state.directives是一个包含(bind,model...)函数的对象 // :DirectiveFunction就是表示gen的类型是一个指令函数 const gen: DirectiveFunction = state.directives[dir.name] if (gen) { // gen函数返回一个Boolean之后我们会提到,这里将结果赋值给needRuntime来表示函数执行是否结束 needRuntime = !!gen(el, dir, state.warn) } if (needRuntime) { hasRuntime = true res += `{name:"${dir.name}",rawName:"${dir.rawName}"${ dir.value ? `,value:(${dir.value}),expression:${JSON.stringify(dir.value)}` : '' }${ dir.arg ? `,arg:"${dir.arg}"` : '' }${ dir.modifiers ? `,modifiers:${JSON.stringify(dir.modifiers)}` : '' }},` } if (hasRuntime) { return res.slice(0, -1) + ']' } } } 复制代码

dir就是上面提到的数组下,res不过就是将这些参数拼接起来,让我们看看它最终长什么样子


v-model 使用场景和源码学习

加上后面的slice方法就是将res字符串的最后一位去掉然后拼接上']'组成一个完整的数组。

model函数 上面 const gen: DirectiveFunction = state.directives[dir. name]是拿出指令名对应的函数,拿model举例。定义在 src/platforms/web/compiler/directives/model.js export default function model ( el: ASTElement, dir: ASTDirective, _warn: Function ): ?boolean{ // 就是needRuntime = !!gen(el, dir, state.warn)传递过来的参数 const value = dir.value const modifiers = dir.modifiers const tag = el.tag const type = el.attrsMap.type // process该对象表示Node所处的当前进程(全局变量)process.env属性返回一个包含用户环境信息的对象使用场景:在development和production不同环境上,配置会有些不同 if (process.env.NODE_ENV !== 'production') { if (tag === 'input' && type === 'file') { warn( `<${el.tag} v-model="${value}" type="file">:\n` + `File inputs are read only. Use a v-on:change listener instead.` ) } } if (el.component) { genComponentModel(el, value, modifiers) return false } else if (tag === 'select') { genSelect(el, value, modifiers) } else if (tag === 'input' && type === 'checkbox') { genCheckboxModel(el, value, modifiers) } else if (tag === 'input' && type === 'radio') { genRadioModel(el, value, modifiers) } else if (tag === 'input' || tag === 'textarea') { genDefaultModel(el, value, modifiers)

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

代码区博客精选文章
分页:12
转载请注明
本文标题:v-model 使用场景和源码学习
本站链接:https://www.codesec.net/view/610752.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(64)