美文网首页
vue-v-model

vue-v-model

作者: 梦行乌托邦 | 来源:发表于2020-08-07 18:39 被阅读0次

    v-model是怎么实现双向绑定的?
    看源码:
    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
    

    以上,有分场景
    自定义组件上的:
    select:change事件

    function genSelect (
      el: ASTElement,
      value: string,
      modifiers: ?ASTModifiers
    ) {
      const number = modifiers && modifiers.number
      const selectedVal = `Array.prototype.filter` +
        `.call($event.target.options,function(o){return o.selected})` +
        `.map(function(o){var val = "_value" in o ? o._value : o.value;` +
        `return ${number ? '_n(val)' : 'val'}})`
    
      const assignment = '$event.target.multiple ? $$selectedVal : $$selectedVal[0]'
      let code = `var $$selectedVal = ${selectedVal};`
      code = `${code} ${genAssignmentCode(value, assignment)}`
      addHandler(el, 'change', code, null, true)
    }
    

    input-checkbox:checked + change

    function genCheckboxModel (
      el: ASTElement,
      value: string,
      modifiers: ?ASTModifiers
    ) {
      const number = modifiers && modifiers.number
      const valueBinding = getBindingAttr(el, 'value') || 'null'
      const trueValueBinding = getBindingAttr(el, 'true-value') || 'true'
      const falseValueBinding = getBindingAttr(el, 'false-value') || 'false'
      addProp(el, 'checked',
        `Array.isArray(${value})` +
        `?_i(${value},${valueBinding})>-1` + (
          trueValueBinding === 'true'
            ? `:(${value})`
            : `:_q(${value},${trueValueBinding})`
        )
      )
      addHandler(el, 'change',
        `var $$a=${value},` +
            '$$el=$event.target,' +
            `$$c=$$el.checked?(${trueValueBinding}):(${falseValueBinding});` +
        'if(Array.isArray($$a)){' +
          `var $$v=${number ? '_n(' + valueBinding + ')' : valueBinding},` +
              '$$i=_i($$a,$$v);' +
          `if($$el.checked){$$i<0&&(${genAssignmentCode(value, '$$a.concat([$$v])')})}` +
          `else{$$i>-1&&(${genAssignmentCode(value, '$$a.slice(0,$$i).concat($$a.slice($$i+1))')})}` +
        `}else{${genAssignmentCode(value, '$$c')}}`,
        null, true
      )
    }
    

    input-radio: checked + change

    function genRadioModel (
      el: ASTElement,
      value: string,
      modifiers: ?ASTModifiers
    ) {
      const number = modifiers && modifiers.number
      let valueBinding = getBindingAttr(el, 'value') || 'null'
      valueBinding = number ? `_n(${valueBinding})` : valueBinding
      addProp(el, 'checked', `_q(${value},${valueBinding})`)
      addHandler(el, 'change', genAssignmentCode(value, valueBinding), null, true)
    }
    

    input-text | textarea:value + (input | change(设置了lazy))

    function genDefaultModel (
      el: ASTElement,
      value: string,
      modifiers: ?ASTModifiers
    ): ?boolean {
      const type = el.attrsMap.type
    
      // warn if v-bind:value conflicts with v-model
      // except for inputs with v-bind:type
      if (process.env.NODE_ENV !== 'production') {
        const value = el.attrsMap['v-bind:value'] || el.attrsMap[':value']
        const typeBinding = el.attrsMap['v-bind:type'] || el.attrsMap[':type']
        if (value && !typeBinding) {
          const binding = el.attrsMap['v-bind:value'] ? 'v-bind:value' : ':value'
          warn(
            `${binding}="${value}" conflicts with v-model on the same element ` +
            'because the latter already expands to a value binding internally',
            el.rawAttrsMap[binding]
          )
        }
      }
    
      const { lazy, number, trim } = modifiers || {}
      const needCompositionGuard = !lazy && type !== 'range'
      const event = lazy
        ? 'change'
        : type === 'range'
          ? RANGE_TOKEN
          : 'input'
    
      let valueExpression = '$event.target.value'
      if (trim) {
        valueExpression = `$event.target.value.trim()`
      }
      if (number) {
        valueExpression = `_n(${valueExpression})`
      }
    
      let code = genAssignmentCode(value, valueExpression)
      if (needCompositionGuard) {
        code = `if($event.target.composing)return;${code}`
      }
    
      addProp(el, 'value', `(${value})`)
      addHandler(el, event, code, null, true)
      if (trim || number) {
        addHandler(el, 'blur', '$forceUpdate()')
      }
    }
    

    相关文章

      网友评论

          本文标题:vue-v-model

          本文链接:https://www.haomeiwen.com/subject/drtfdktx.html