lgwebdream/FE-Interview

Day101:Vue v-model 是如何实现的,语法糖实际是什么

Genzhen opened this issue · 2 comments

每日一题会在下午四点在交流群集中讨论,五点 Github、交流群同步更新答案

扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。

每日一题会在下午四点在交流群集中讨论,五点 Github、交流群同步更新答案

一、语法糖

指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。糖在不改变其所在位置的语法结构的前提下,实现了运行时的等价。可以简单理解为,加糖后的代码编译后跟加糖前一样,代码更简洁流畅,代码更语义自然.

二、实现原理

1.作用在普通表单元素上

动态绑定了 input 的 value 指向了 messgae 变量,并且在触发 input 事件的时候去动态把 message 设置为目标值

<input v-model="sth" />
//  等同于
<input 
    v-bind:value="message" 
    v-on:input="message=$event.target.value"
>
//$event 指代当前触发的事件对象;
//$event.target 指代当前触发的事件对象的dom;
//$event.target.value 就是当前dom的value值;
//在@input方法中,value => sth;
//在:value中,sth => value;

2.作用在组件上

在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件

本质是一个父子组件通信的语法糖,通过prop和$.emit实现

因此父组件v-model语法糖本质上可以修改为 '<child :value="message" @input="function(e){message = e}"></child>'

在组件的实现中,我们是可以通过 v-model属性 来配置子组件接收的prop名称,以及派发的事件名称。

例子

// 父组件
<aa-input v-model="aa"></aa-input>
// 等价于
<aa-input v-bind:value="aa" v-on:input="aa=$event.target.value"></aa-input>

// 子组件:
<input v-bind:value="aa" v-on:input="onmessage"></aa-input>

props:{value:aa,}
methods:{
    onmessage(e){
        $emit('input',e.target.value)
    }
}

默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event

但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

js 监听input 输入框输入数据改变,用oninput ,数据改变以后就会立刻出发这个事件。

通过input事件把数据$emit 出去,在父组件接受。

父组件设置v-model的值为input$emit过来的值。

v-model指令在表单input,textarea,select等元素上创建双向数据绑定,本质上是语法糖
v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件

text 和 textarea 元素使用 value 属性和 input 事件;
checkbox 和 radio 使用 checked 属性和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。

<input v-model='something'>
相当于
<input :value="something" @input="something = $event.target.value">

v-model的缺点和解决方法
    缺点:
        v-model应用到组件上,它会默认把value作为组件的属性,把input作为给组件绑定的事件时的事件名
        有时候我们不想用value当做默认的属性名和不想input作为给组件绑定的时间时的事件名
    
    解决方法:
        在vue2.2版本之后,可以在定义组件时通过model选项方式定制prop/event
        export default{
              model: {
                 prop: 'num', // 自定义属性名
                 event: 'addNum' // 自定义事件名
              },
        }