万物皆可v-model,组件封装神器!

428 阅读1分钟

v-model原理

先看一个例子

<el-input v-model='value' />

这是我们在开发中常用的输入框的双向绑定,他实际的原理是

<el-input v-bind:value="value" v-on:input="value=$event.target.value">

v-model的原理就是v-bind数据绑定与v-on处理函数绑定的语法糖。

日常开发中会遇到很多种需要对组件进行封装或者已有组件的二次封装工作,而且不限于表单组件,在vue中2.2后新增了model语法,可以更好的实现业务组件的封装。

model官网解释

允许一个自定义组件在使用 v-model 时定制 prop 和 event。默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

用法

假如我们有一个需求,需要对已有ui组件库中的input做一下二次封装,所有项目中使用到的输入框都要限制字数0-100,原有组件是支持这个功能的,但是对于项目中大量使用的input来说,在每一个input上添加maxlength以及minlength会特别麻烦。

我们以element-ui的el-input组件来做一个简单的例子, 组件代码如下

<template>
  <div>
    <el-input :value='currentValue' @change='onChange' :maxlength='100' :minlength='0' />
  </div>
</template>

<script>
export default {
  name: 'myInput',
  data() {
    return {
      currentValue: this.value
    }
  },
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    value: {
      type: String
    }
  },
  watch: {
    value: {
      handler() {
        this.currentValue = value
      }
    }
  },
  methods: {
    onChange(val) {
      this.$emit('change', val)
    }
  }
}
</script>

上述组件代码中,我们使用model属性来指定prop以及event,当我们在父组件中使用的时候,只需要绑定v-model属性。

<template>
  <my-input v-model='myInputValue' />
</template>

这样一个数据双向绑定的组件就封装完成了。

注意

  1. 内部定义currentValue的意义在于保证单向数据流,输入框本身的值是由父组件传入的value决定的,不能由子组件内部改变,当发生change事件后,由子组件emit一个事件触发父组件值的变化,再由子组件中的watch监听value变化重新给currentValue赋值

  2. this.$emit('change', val)中的事件名称必须和model: {prop: 'value',event:'change'},中的event名称一致

  3. model的属性不只限于表单组件,任何形式的组件都可以使用这个特性,来实现v-model