Преглед изворни кода

refactor: extract universal v-model codegen code and update weex v-model codegen

Evan You пре 9 година
родитељ
комит
6cbee6b286

+ 127 - 0
src/compiler/directives/model.js

@@ -0,0 +1,127 @@
+/* @flow */
+
+/**
+ * Cross-platform code generation for component v-model
+ */
+export function genComponentModel (
+  el: ASTElement,
+  value: string,
+  modifiers: ?ASTModifiers
+): ?boolean {
+  const { number, trim } = modifiers || {}
+
+  let valueExpression = 'value'
+  if (trim) {
+    valueExpression = `(typeof value === 'string' ? value.trim() : value)`
+  }
+  if (number) {
+    valueExpression = `_n(${valueExpression})`
+  }
+
+  el.model = {
+    value: `(${value})`,
+    callback: `function (value) {${genAssignmentCode(value, valueExpression)}}`
+  }
+}
+
+/**
+ * Cross-platform codegen helper for generating v-model value assignment code.
+ */
+export function genAssignmentCode (
+  value: string,
+  assignment: string
+): string {
+  const modelRs = parseModel(value)
+  if (modelRs.idx === null) {
+    return `${value}=${assignment}`
+  } else {
+    return `var $$exp = ${modelRs.exp}, $$idx = ${modelRs.idx};` +
+      `if (!Array.isArray($$exp)){` +
+        `${value}=${assignment}}` +
+      `else{$$exp.splice($$idx, 1, ${assignment})}`
+  }
+}
+
+/**
+ * parse directive model to do the array update transform. a[idx] = val => $$a.splice($$idx, 1, val)
+ *
+ * for loop possible cases:
+ *
+ * - test
+ * - test[idx]
+ * - test[test1[idx]]
+ * - test["a"][idx]
+ * - xxx.test[a[a].test1[idx]]
+ * - test.xxx.a["asa"][test1[idx]]
+ *
+ */
+
+let len, str, chr, index, expressionPos, expressionEndPos
+
+export function parseModel (val: string): Object {
+  str = val
+  len = str.length
+  index = expressionPos = expressionEndPos = 0
+
+  if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) {
+    return {
+      exp: val,
+      idx: null
+    }
+  }
+
+  while (!eof()) {
+    chr = next()
+    /* istanbul ignore if */
+    if (isStringStart(chr)) {
+      parseString(chr)
+    } else if (chr === 0x5B) {
+      parseBracket(chr)
+    }
+  }
+
+  return {
+    exp: val.substring(0, expressionPos),
+    idx: val.substring(expressionPos + 1, expressionEndPos)
+  }
+}
+
+function next (): number {
+  return str.charCodeAt(++index)
+}
+
+function eof (): boolean {
+  return index >= len
+}
+
+function isStringStart (chr: number): boolean {
+  return chr === 0x22 || chr === 0x27
+}
+
+function parseBracket (chr: number): void {
+  let inBracket = 1
+  expressionPos = index
+  while (!eof()) {
+    chr = next()
+    if (isStringStart(chr)) {
+      parseString(chr)
+      continue
+    }
+    if (chr === 0x5B) inBracket++
+    if (chr === 0x5D) inBracket--
+    if (inBracket === 0) {
+      expressionEndPos = index
+      break
+    }
+  }
+}
+
+function parseString (chr: number): void {
+  const stringQuote = chr
+  while (!eof()) {
+    chr = next()
+    if (chr === stringQuote) {
+      break
+    }
+  }
+}

+ 0 - 84
src/compiler/helpers.js

@@ -100,87 +100,3 @@ export function getAndRemoveAttr (el: ASTElement, name: string): ?string {
   }
   return val
 }
-
-let len, str, chr, index, expressionPos, expressionEndPos
-
-/**
- * parse directive model to do the array update transform. a[idx] = val => $$a.splice($$idx, 1, val)
- *
- * for loop possible cases:
- *
- * - test
- * - test[idx]
- * - test[test1[idx]]
- * - test["a"][idx]
- * - xxx.test[a[a].test1[idx]]
- * - test.xxx.a["asa"][test1[idx]]
- *
- */
-
-export function parseModel (val: string): Object {
-  str = val
-  len = str.length
-  index = expressionPos = expressionEndPos = 0
-
-  if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) {
-    return {
-      exp: val,
-      idx: null
-    }
-  }
-
-  while (!eof()) {
-    chr = next()
-    /* istanbul ignore if */
-    if (isStringStart(chr)) {
-      parseString(chr)
-    } else if (chr === 0x5B) {
-      parseBracket(chr)
-    }
-  }
-
-  return {
-    exp: val.substring(0, expressionPos),
-    idx: val.substring(expressionPos + 1, expressionEndPos)
-  }
-}
-
-function next (): number {
-  return str.charCodeAt(++index)
-}
-
-function eof (): boolean {
-  return index >= len
-}
-
-function isStringStart (chr: number): boolean {
-  return chr === 0x22 || chr === 0x27
-}
-
-function parseBracket (chr: number): void {
-  let inBracket = 1
-  expressionPos = index
-  while (!eof()) {
-    chr = next()
-    if (isStringStart(chr)) {
-      parseString(chr)
-      continue
-    }
-    if (chr === 0x5B) inBracket++
-    if (chr === 0x5D) inBracket--
-    if (inBracket === 0) {
-      expressionEndPos = index
-      break
-    }
-  }
-}
-
-function parseString (chr: number): void {
-  const stringQuote = chr
-  while (!eof()) {
-    chr = next()
-    if (chr === stringQuote) {
-      break
-    }
-  }
-}

+ 2 - 34
src/platforms/web/compiler/directives/model.js

@@ -2,7 +2,8 @@
 
 import config from 'core/config'
 import { isIE } from 'core/util/env'
-import { addHandler, addProp, getBindingAttr, parseModel } from 'compiler/helpers'
+import { addHandler, addProp, getBindingAttr } from 'compiler/helpers'
+import { genComponentModel, genAssignmentCode } from 'compiler/directives/model'
 
 let warn
 
@@ -183,36 +184,3 @@ function genDefaultModel (
     addHandler(el, 'blur', '$forceUpdate()')
   }
 }
-
-function genComponentModel (
-  el: ASTElement,
-  value: string,
-  modifiers: ?ASTModifiers
-): ?boolean {
-  const { number, trim } = modifiers || {}
-
-  let valueExpression = 'value'
-  if (trim) {
-    valueExpression = `(typeof value === 'string' ? value.trim() : value)`
-  }
-  if (number) {
-    valueExpression = `_n(${valueExpression})`
-  }
-
-  el.model = {
-    value,
-    callback: `function (value) {${genAssignmentCode(value, valueExpression)}}`
-  }
-}
-
-function genAssignmentCode (value: string, assignment: string): string {
-  const modelRs = parseModel(value)
-  if (modelRs.idx === null) {
-    return `${value}=${assignment}`
-  } else {
-    return `var $$exp = ${modelRs.exp}, $$idx = ${modelRs.idx};` +
-      `if (!Array.isArray($$exp)){` +
-        `${value}=${assignment}}` +
-      `else{$$exp.splice($$idx, 1, ${assignment})}`
-  }
-}

+ 14 - 19
src/platforms/weex/compiler/directives/model.js

@@ -1,13 +1,18 @@
 /* @flow */
 
-import { addHandler, addAttr, parseModel } from 'compiler/helpers'
+import { addHandler, addAttr } from 'compiler/helpers'
+import { genComponentModel, genAssignmentCode } from 'compiler/directives/model'
 
 export default function model (
   el: ASTElement,
   dir: ASTDirective,
   _warn: Function
 ): ?boolean {
-  genDefaultModel(el, dir.value, dir.modifiers)
+  if (el.tag === 'input' || el.tag === 'textarea') {
+    genDefaultModel(el, dir.value, dir.modifiers)
+  } else {
+    genComponentModel(el, dir.value, dir.modifiers)
+  }
 }
 
 function genDefaultModel (
@@ -15,25 +20,15 @@ function genDefaultModel (
   value: string,
   modifiers: ?ASTModifiers
 ): ?boolean {
-  const { lazy, trim } = modifiers || {}
+  const { lazy, trim, number } = modifiers || {}
   const event = lazy ? 'change' : 'input'
-  const isNative = el.tag === 'input' || el.tag === 'textarea'
-  const valueExpression = isNative
-    ? `$event.target.attr.value${trim ? '.trim()' : ''}`
-    : `$event`
+
+  let valueExpression = `$event.target.attr.value${trim ? '.trim()' : ''}`
+  if (number) {
+    valueExpression = `_n(${valueExpression})`
+  }
+
   const code = genAssignmentCode(value, valueExpression)
   addAttr(el, 'value', `(${value})`)
   addHandler(el, event, code, null, true)
 }
-
-function genAssignmentCode (value: string, assignment: string): string {
-  const modelRs = parseModel(value)
-  if (modelRs.idx === null) {
-    return `${value}=${assignment}`
-  } else {
-    return `var $$exp = ${modelRs.exp}, $$idx = ${modelRs.idx};` +
-      `if (!Array.isArray($$exp)){` +
-        `${value}=${assignment}}` +
-      `else{$$exp.splice($$idx, 1, ${assignment})}`
-  }
-}

+ 1 - 1
test/unit/features/directives/model-parse.spec.js

@@ -1,4 +1,4 @@
-import { parseModel } from 'compiler/helpers'
+import { parseModel } from 'compiler/directives/model'
 
 describe('model expression parser', () => {
   it('parse object dot notation', () => {

+ 2 - 14
test/weex/compiler/v-model.spec.js

@@ -14,28 +14,16 @@ describe('compile v-model', () => {
   it('should compile other component with whole $event as the value', () => {
     const { render, staticRenderFns, errors } = compile(`<div><foo v-model="x" /></div>`)
     expect(render).not.toBeUndefined()
-    expect(render).toMatch(strToRegExp(`attrs:{"value":(x)}`))
-    expect(render).toMatch(strToRegExp(`on:{"input":function($event){x=$event}}`))
-    expect(staticRenderFns).toEqual([])
-    expect(errors).toEqual([])
-  })
-
-  it('should compile with lazy modifier', () => {
-    const { render, staticRenderFns, errors } = compile(`<div><foo v-model.lazy="x" /></div>`)
-    expect(render).not.toBeUndefined()
-    expect(render).toMatch(strToRegExp(`attrs:{"value":(x)}`))
-    expect(render).toMatch(strToRegExp(`on:{"change":function($event){x=$event}}`))
+    expect(render).toMatch(strToRegExp(`model:{value:(x),callback:function (value) {x=value}}`))
     expect(staticRenderFns).toEqual([])
     expect(errors).toEqual([])
   })
 
   it('should compile with trim modifier for modelable native component', () => {
-    const { render, staticRenderFns, errors } = compile(`<div><input v-model.trim="x" /><foo v-model.trim="y" /></div>`)
+    const { render, staticRenderFns, errors } = compile(`<div><input v-model.trim="x" /></div>`)
     expect(render).not.toBeUndefined()
     expect(render).toMatch(strToRegExp(`attrs:{"value":(x)}`))
-    expect(render).toMatch(strToRegExp(`attrs:{"value":(y)}`))
     expect(render).toMatch(strToRegExp(`on:{"input":function($event){x=$event.target.attr.value.trim()}}`))
-    expect(render).toMatch(strToRegExp(`on:{"input":function($event){y=$event}}`))
     expect(staticRenderFns).toEqual([])
     expect(errors).toEqual([])
   })