关于 v-model 的一点思考

本文来自「Vue 虚拟实验室」的小伙伴,本文详细讲解了 v-model 的使用

@xyjwyq

在 Vue 中 v-model 指令的使用场景,主要分为两种:

1. 用于一些表单元素;

2. 自定义组件;

下面,针对这两种场景,进行一些总结。

表单元素中使用 v-model

v-model 指令在表单元素上的使用,主要是 input、textarea 以及 select 元素,而 v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

• text 和 textarea 元素使用 value 属性和 input 事件;

• checkbox 和 radio 使用 checked 属性和 change 事件;

• select 字段将 value 作为 prop 并将 change 作为事件。

下面从基本使用,编译结果分析以及源码三部分进行理解

1、基本使用


value: { { value }}

2、编译结果

const tplCOmplier = require('vue-template-compiler')
const res = tplCOmplier.compile('')
console.log(res)


/**
* 编译成之后输出的render
 with (this) {
    return _c('input', {
      // 该指令作用,是对输入法的一些校验,暂不考虑
        directives: [{
            name: "model",
            rawName: "v-model",
            value: (value),
            expression: "value"
        }],
        attrs: {
            "type": "text"
        },
        domProps: {
            "value": (value)
        },
        on: {
            "input": function ($event) { 
              if ($event.target.composing) return; 
              value = $event.target.value }
        }
    })
}
 */


从编译结果可以看出,在渲染时,会 对不同的表单元素,添加不同的属性和事件(由篇幅问题,不将编译结果一一列举);

3、源码

// src\platforms\web\compiler\directives\model.js 
if (el.component) {
    genComponentModel(el, value, modifiers)
    // component v-model doesn't need extra runtime
    return false
  } else if (tag === 'select') {
    genSelect(el, value, modifiers)
  } else if (tag === 'input' && type === 'checkbox') {
    genCheckboxModel(el, value, modifiers)
  } else if (tag === 'input' && type === 'radio') {
    genRadioModel(el, value, modifiers)
  } else if (tag === 'input' || tag === 'textarea') {
    genDefaultModel(el, value, modifiers)
  } else if (!config.isReservedTag(tag)) {
    genComponentModel(el, value, modifiers)
    // component v-model doesn't need extra runtime
    return false
  }

4、自定义 v-model


Vue.component('el-checkbox', {
    template: ``,
    props: ['checkValue'],
    model: {
        prop: 'checkValue',
        event: 'changeEvent'
    }
});

5、源码中自定义 v-model 的处理

function transformModel (options, data: any) {
  // 若没有传递model配置,则默认为 value属性和input事件的语法糖
  const prop = (options.model && options.model.prop) || 'value'
  const event = (options.model && options.model.event) || 'input'
  ;(data.attrs || (data.attrs = {}))[prop] = data.model.value
  const on = data.on || (data.on = {})
  const existing = on[event]
  const callback = data.model.callback
  if (isDef(existing)) {
    if (
      Array.isArray(existing)
        ? existing.indexOf(callback) === -1
        : existing !== callback
    ) {
      on[event] = [callback].concat(existing)
    }
  } else {
    on[event] = callback
  }
}

推荐阅读:

让 Class 与 Style 动起来

动静结合 · Vue 模板

Vue 模板的功臣 · 指令

你可能感兴趣的:(关于 v-model 的一点思考)