v-model是响应式的吗?

1,827 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

前情提要

我们都知道在vue中数据是响应式的,是双向绑定的。那么就有了疑问:v-model指令是响应式的吗?
答:不是。

什么是响应式?(简讲,后面会有文章深度剖析)

  • 首先我们要了解响应式的概念是什么?
    • 总结一句话就是:当视图模型(VM)中的数据模型(M)发生改变时, 视图(V)就会进行更新。
  • 而实现原理是:利用 Object.defineProperty 进行 数据劫持 同时结合观察者模式(发布 / 订阅模式)来实现数据双向绑定。
    • 数据劫持利用Object.defineProperty 中的 getter/setter,数据改变就执行 watcher
    • 发布/订阅模式它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。

v-model到底是什么?

  • v-model实际只是一个语法糖而已。主要依赖value属性的绑定和input原生事件的触发来实现。
  • 给组件添加v-model指令时,默认会把value作为组件的属性,然后把input值作为给组件绑定事件时的事件名。
  • 等价代码:
<input v-model="str" />
// 等价于
<input :value="str" @input="$event.target.value" />
// input标签在HTML5中新增了oninput事件,与onchange事件不同的是,会在每次输入动作时触发。而onchange是在输入完成后才会触发。所以这样就能保证每次输入即页面展示。
  • 上面的那种是指在原生标签中的表现。还有一种是在自定义组件中的表现。主要是通过配置model实现v-model的prop属性与event事件的自定义
// 组件调用:
<customComponent v-model="test"></customComponent>
// 自定义组件内部
<template>
  <div>
    <div v-for="item in list" :key="item" @click="change(item)" :class="item == currentValue ? 'actived' : ''">
      {{ item }}
    </div>
  </div>
</template>
<script>
export default {
  //定义实现v-modal的属性与事件
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
      // 绑定的值
    value: {
      type: [String, Number],
      defalut: ''
    },
    // 数据源
    list: {
      type: Array,
      default: () => []
    }
  },
  watch: {
    value(newValue) {
      this.currentValue = newValue;
    }
  },
  data() {
    return {
      // 当前选中的值
      currentValue: ''
    }
  },
  created() {
    // 组件初始化的时候先获取一次值
    this.currentValue = this.value
  },
  methods: {
    change(item) {
      // 发送change事件,父组件会将接收到的值赋给组件定义的变量。
      // 同时也可以在父组件里显示的调用change事件。
      this.$emit('change', item)
    }
  }
}
</script>
<style scoped>
.actived {
  background: red;
  color: white;
}
</style>

WX20220414-110552@2x.png