用基础语法prop和$emit来解释v-model

242 阅读1分钟

v-model是语法糖,目的是在使用的过程中以v-model一个指令完成数据的双向绑定。以下通过Vue中的基础语法对v-modelinut组件中的使用进行模拟,以达到用已知解释未知的目的。

1、input中使用

语法糖v-model:

new Vue({
  el: "#app",
  data() {
    return {
      msg: "hello world!"
    };
  },
  template: `<div>
    <input v-model="msg" placeholder="edit me">
    <p>msg is: {{ msg }}</p>
  </div>`
});

当前例子中,双向绑定指的是:数据msg引起了视图的改变,页面展示hello world!。视图input框中输入hello Vue!,也引起数据msg的改变,其值变为hello Vue!

基础语法模拟:

new Vue({
  el: "#app",
  data() {
    return {
      msg: "hello world!"
    };
  },
  template: `<div>
    <input @input='inputEvent' :value='msg' placeholder="edit me">
    <p>msg is: {{ msg }}</p>
  </div>`,
  methods: {
    inputEvent($event) {
      this.msg = $event.target.value
    }
  }
});

在视图input上绑定属性:value='msg',起初视图渲染展示hello world!。当视图发生改变展示为hello world!时,通过监听input中的input事件,通过this.msg = $event.target.valueinput中的数据赋值给数据msg,以达到双向绑定的目的。

2、组件中使用

语法糖v-model:

const inputBox = {
  template: `<input @input="$emit('input', $event.target.value)">`,
};

new Vue({
  el: "#app",
  template: `<div>
    <input-box v-model="msg"></input-box>
    <p>{{msg}}</p>
  </div>`,
  components: {
    inputBox
  },
  data() {
    return {
      msg: 'hello world!'
    };
  }
});

例子中父组件msg的数据为hello world!,子组件中的input视图也渲染成了hello world!。当子组件中的视图input值改变为hello Vue!时,父组件中的msg也变成了hello Vue!。数据从父组件到子组件,再从子组件到父组件,即是双向数据流。

基础语法模拟:

const inputBox = {
  template: `<input :value="msg" @input="$emit('input', $event.target.value)">`,
  props: {
    msg: String,
  }
};

new Vue({
  el: "#app",
  template: `<div>
    <input-box :msg="msg" @input="changeMsg"></input-box>
    <p>{{msg}}</p>
  </div>`,
  components: {
    inputBox
  },
  data() {
    return {
      msg: 'hello world!'
    };
  },
  methods: {
    changeMsg(v) {
      this.msg = v;
    }
  }
});

模拟的例子中,父组件通过:msg="msg"的方式向子组件传递数据,然后子组件数据发生改变时会通过$emit的方式触发input事件,父组件通过@input=changeMsg的方式接收并修改msg的值。从父组件到子组件通过props完成,从子组件到父组件通过$emit完成,实现了数据双向流动的目的。

总结

用熟知的prop$emit来理解语法糖v-model将会更容易理解。