iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 24
0
Modern Web

技術在走,Vue.js 要有系列 第 24

|D24| 從原始碼看 Vue 擴展 (3) - v-model

  • 分享至 

  • xImage
  •  

以下面範例來說,在 input 輸入的內容,message 會同步變化

<div id="app">
  <input v-model="message">
  <p>Message is: {{ message }}</p>
</div>
var vm = new Vue({
  el: '#app',
  data() {
    return {
      message: ''
    }
  }
})

genDefaultModel 函數裡 modifiers 會影響 eventvalueExpression 的值。
以上面例子來說,eventinputvalueExpression$event.target.value。然後會執行 genAssignmentCode 生成 code 程式碼

// src/platforms/web/compiler/directives/model.js

function genDefaultModel (
  el: ASTElement,
  value: string,
  modifiers: ?ASTModifiers
): ?boolean {
  //...

  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()')
  }
}

//...

export function parseModel (val: string): ModelParseResult {
  val = val.trim()
  len = val.length

  if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) {
    index = val.lastIndexOf('.')
    if (index > -1) {
      return {
        exp: val.slice(0, index),
        key: '"' + val.slice(index + 1) + '"'
      }
    } else {
      return {
        exp: val,
        key: null
      }
    }
  }

  //...

  return {
    exp: val.slice(0, expressionPos),
    key: val.slice(expressionPos + 1, expressionEndPos)
  }
}

// src/compiler/directives/model.js
 /*************************************************
    定義 genAssignmentCode 
 **************************************************/
export function genAssignmentCode (
  value: string,
  assignment: string
): string {
  const res = parseModel(value)
  if (res.key === null) {
    return `${value}=${assignment}`
  } else {
    return `$set(${res.exp}, ${res.key}, ${assignment})`
  }
}

genAssignmentCode 先對 v-model 對應的 value 解析,對上面例子,value 就是 messgae
messgae 參數傳入 parseModelparseModel 的回傳值得到 res.key === null,所以 genAssignmentCode 會回傳 message=$event.target.value,接著 needCompositionGuard 為 true,最後得到code = if($event.target.composing)return;message=$event.target.value

// src/platforms/web/compiler/directives/model.js

function genDefaultModel (
  el: ASTElement,
  value: string,
  modifiers: ?ASTModifiers
): ?boolean {
  //...

  const needCompositionGuard = !lazy && type !== 'range'

  let code = genAssignmentCode(value, valueExpression)
  if (needCompositionGuard) {
    code = `if($event.target.composing)return;${code}`
  }
}

接著執行 addPropaddHandler

// src/platforms/web/compiler/directives/model.js

function genDefaultModel (
  el: ASTElement,
  value: string,
  modifiers: ?ASTModifiers
): ?boolean {
  //...

  addProp(el, 'value', `(${value})`)
  addHandler(el, event, code, null, true)
  
  //...
}

此處對 el 加上一個 prop,相當於在 input 上動態綁定 value 和對 el 加上 input 事件,以模板來想如下

<input
  :value="message"
  @input="message=$event.target.value"
>

上一篇
|D23| 從原始碼看 Vue 擴展 (1) - 自定義 event
下一篇
|D25| 從原始碼看 Vue 擴展 (4) - slot
系列文
技術在走,Vue.js 要有30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言