面试官:你真的了解v-model吗?

880 阅读2分钟

一、v-model的本质是语法糖

v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据】 -- 官方文档

什么是语法糖?

语法糖,简单来说就是【便捷写法】。

v-modelv-bindv-on的语法糖,即,v-model算是v-bindv-on的简洁写法。

我们以input为例说明一下v-model

<input type="text" v-model="value" />
等价于
<input type="text" :value="value" @input="value = $event.target.value"/>
等价于
<input type="text" v:bind:value="value" v-on:input="value = $event.target.value"/>

本质上来说v-model是完成事件绑定和事件监听的语法糖。

二、 v-model 仅仅是语法糖吗?(冷知识)

v-model不仅仅是语法糖,它还有副作用。

副作用如下:如果v-model绑定的是响应式对象上某个不存在的属性,那么vue会悄悄地添加这个属性,并让它响应式。

举个例子,看下面的代码

template
<el-input type="text" v-model="user.age"/>

js
export default {
  data() {
    return {
      user: {
        name: '张三',
      }
    }
  }
}

响应式数据中没有定义user.age属性,但是template里却用了v-model绑定了user.age,猜一猜当你输入时会发生什么?

6e187621b3ee9b35499e56cd11b9a8b7.png 答案是:user上会新增age属性,并且age这个属性还是响应式的。这就是【副作用】带来的效果。

三、v-model是双向绑定还是单相数据流?

3.1 v-model是双向绑定吗?

是,官方说是。 [你可以用v-model指令在表单<input><textarea><select>元素上创建双向数据绑定]。 --vue2官方文档

我们使用v-bind实现单项的数据绑定,也就是通过父组件向子组件传入数据;在这基础上,我们绑定了input事件监听,在输入的过程中通过$emit触发数据更新,从而达到双向数据绑定。

3.2 那v-model是单向数据流吗?

是的,它甚至是单相数据流的典型。

什么是单向数据流?

子组件不能改变父组件传递给它的prop属性,推荐的做法是它抛出事件,通知父组件自行改变绑定的值。而这完全符合v-model的做法。

【单相数据流】总结起来其实也就8个字:【数据向下,事件向上】。

四、在组件中使用v-model

父组件

<template>
  <div class="container">
    <!-- 在使用中组件 -->
    <Child v-model="value"></Child>
    <!-- 等同于 -->
    <!-- <Child v-bind:value="value"  v-on:input="input"></Child> -->
    <!-- 等同于 -->
    <!-- <Child :value="value" @input="input"></Child> -->

    {{ value }}
  </div>
</template>

<script>
// 引入组件
import Child from "./components/child";
export default {
  // 注册组件
  components: {
    Child
  },
  data() {
    return {
      value: "22"
    };
  },
  methods: {
    input(data) {
      console.log(data);
      this.value = data;
    }
  }
};
</script>

子组件

<template>
  <!-- 2. 监听 input 事件的出发 -->
  <input type="text" :value="value" @input="input" />
</template>

<script>
export default {
  // 1. 接受父级传递的值
  props: {
    value: {
      type: String,
      default: ""
    }
  },
  methods: {
    input(event) {
      this.$emit("input", event.target.value);
    }
  }
};
</script>

v-model这就实现了双向数据绑定,实际上它就是通过Vue提供的事件机制。即在子组件通过$emit()触发一个事件,在父组件使用v-model即可。