Evan You 10 лет назад
Родитель
Сommit
2082eb9290

+ 3 - 5
src/compiler/codegen/directives/html.js

@@ -1,8 +1,6 @@
+import { addProp } from '../../helpers'
+
 export function html (el, dir) {
   if (!dir.value) return
-  if (!el.props) el.props = []
-  el.props.push({
-    name: 'innerHTML',
-    value: `(${dir.value})`
-  })
+  addProp(el, 'innerHTML', `(${dir.value})`)
 }

+ 11 - 35
src/compiler/codegen/directives/model.js

@@ -1,8 +1,6 @@
-import { addHandler } from '../../helpers'
+import { addHandler, addProp, getBindingAttr } from '../../helpers'
 
 export function model (el, dir) {
-  if (!el.events) el.events = {}
-  if (!el.props) el.props = []
   const value = dir.value
   const modifiers = dir.modifiers
   if (el.tag === 'select') {
@@ -26,19 +24,13 @@ export function model (el, dir) {
 }
 
 function genCheckboxModel (el, value) {
-  addHandler(el.events, 'change', `${value}=$event.target.checked`)
-  el.props.push({
-    name: 'checked',
-    value: `!!(${value})`
-  })
+  addProp(el, 'checked', `!!(${value})`)
+  addHandler(el, 'change', `${value}=$event.target.checked`)
 }
 
 function genRadioModel (el, value) {
-  addHandler(el.events, 'change', `${value}=$event.target.value`)
-  el.props.push({
-    name: 'checked',
-    value: `(${value}==${getInputValue(el)})`
-  })
+  addProp(el, 'checked', `(${value}==${getBindingAttr(el, 'value')})`)
+  addHandler(el, 'change', `${value}=$event.target.value`)
 }
 
 function genDefaultModel (el, value, modifiers) {
@@ -51,15 +43,11 @@ function genDefaultModel (el, value, modifiers) {
   let code = number || type === 'number'
     ? `${value}=Number($event.target.value)`
     : `${value}=$event.target.value`
-
   if (needCompositionGuard) {
     code = `if($event.target.composing)return;${code}`
   }
-  addHandler(el.events, event, code)
-  el.props.push({
-    name: 'value',
-    value: `(${value})`
-  })
+  addProp(el, 'value', `(${value})`)
+  addHandler(el, event, code)
   if (needCompositionGuard) {
     // return runtime directive code to help with composition events
     return '{def:__resolveDirective__("model")},'
@@ -67,15 +55,12 @@ function genDefaultModel (el, value, modifiers) {
 }
 
 function genSelect (el, value) {
-  addHandler(el.events, 'change', `${value}=$event.target.value`)
-  el.props.push({
-    name: 'value',
-    value: `(${value})`
-  })
+  addProp(el, 'value', `(${value})`)
+  addHandler(el, 'change', `${value}=$event.target.value`)
 }
 
 function genMultiSelect (el, value) {
-  addHandler(el.events, 'change',
+  addHandler(el, 'change',
     `${value}=Array.prototype.filter
     .call($event.target.options,function(o){return o.selected})
     .map(function(o){return o.value})`)
@@ -83,16 +68,7 @@ function genMultiSelect (el, value) {
   for (let i = 0; i < el.children.length; i++) {
     let c = el.children[i]
     if (c.tag === 'option') {
-      (c.props || (c.props = [])).push({
-        name: 'selected',
-        value: `(${value}).indexOf(${getInputValue(c)})>-1`
-      })
+      addProp(c, 'selected', `(${value}).indexOf(${getBindingAttr(c, 'value')})>-1`)
     }
   }
 }
-
-function getInputValue (el) {
-  return el.attrsMap.value
-    ? JSON.stringify(el.attrsMap.value)
-    : el.attrsMap['v-bind:value'] || el.attrsMap[':value']
-}

+ 40 - 1
src/compiler/helpers.js

@@ -1,6 +1,29 @@
 import { isArray } from '../shared/util'
 
-export function addHandler (events, name, value, modifiers) {
+export function getBindingAttr (el, name, getStatic) {
+  const staticValue = getStatic !== false && getAndRemoveAttr(el, name)
+  return staticValue
+    ? JSON.stringify(staticValue)
+    : (getAndRemoveAttr(el, ':' + name) || getAndRemoveAttr(el, 'v-bind:' + name))
+}
+
+export function getAndRemoveAttr (el, name) {
+  let val
+  if ((val = el.attrsMap[name]) != null) {
+    el.attrsMap[name] = null
+    const list = el.attrsList
+    for (let i = 0, l = list.length; i < l; i++) {
+      if (list[i].name === name) {
+        list.splice(i, 1)
+        break
+      }
+    }
+  }
+  return val
+}
+
+export function addHandler (el, name, value, modifiers) {
+  const events = (el.events || (el.events = {}))
   // check capture modifier
   if (modifiers && modifiers.capture) {
     delete modifiers.capture
@@ -16,3 +39,19 @@ export function addHandler (events, name, value, modifiers) {
     events[name] = newHandler
   }
 }
+
+export function addProp (el, name, value) {
+  (el.props || (el.props = [])).push({ name, value })
+}
+
+export function addAttr (el, name, value) {
+  (el.attrs || (el.attrs = [])).push({ name, value })
+}
+
+export function addDirective (el, name, value, arg, modifiers) {
+  (el.directives || (el.directives = [])).push({ name, value, arg, modifiers })
+}
+
+export function addStyle (el, name, value) {
+
+}

+ 17 - 87
src/compiler/parser/index.js

@@ -1,8 +1,15 @@
 import { decodeHTML } from 'entities'
 import { parseHTML } from './html-parser'
 import { parseText } from './text-parser'
-import { addHandler } from '../helpers'
 import { hyphenate, makeMap } from '../../shared/util'
+import {
+  getAndRemoveAttr,
+  addProp,
+  addAttr,
+  addHandler,
+  addDirective,
+  getBindingAttr
+} from '../helpers'
 
 const dirRE = /^v-|^@|^:/
 const bindRE = /^:|^v-bind:/
@@ -26,51 +33,6 @@ const baseWarn = msg => console.error(`[Vue parser]: ${msg}`)
 /**
  * Convert HTML string to AST.
  *
- * There are 3 types of nodes:
- *
- * - Element: {
- *     // base info
- *     tag: String,
- *     plain: Boolean,
- *     attrsList: Array,
- *     attrsMap: Object,
- *     parent: Element,
- *     children: Array,
- *
- *     attrs: Array
- *     props: Array
- *     directives: Array
- *
- *     pre: Boolean
- *
- *     if: String (expression)
- *     else: Boolean
- *     elseBlock: Element
- *
- *     for: String
- *     iterator: String
- *     alias: String
- *
- *     staticClass: String
- *     classBinding: String
- *
- *     styleBinding: String
- *
- *     render: Boolean
- *     renderName: String
- *     renderArgs: String
- *
- *     slotName: String
- *   }
- *
- * - Expression: {
- *     expression: String (expression)
- *   }
- *
- * - Text: {
- *     text: String
- *   }
- *
  * @param {String} template
  * @param {Object} options
  * @return {Object}
@@ -295,33 +257,24 @@ function processRender (el) {
 
 function processSlot (el) {
   if (el.tag === 'slot') {
-    el.slotName = el.attrsMap.name
-      ? `"${el.attrsMap.name}"`
-      : (el.attrsMap[':name'] || el.attrsMap['v-bind:name'])
+    el.slotName = getBindingAttr(el, 'name')
   }
 }
 
 function processComponent (el) {
   if (el.tag === 'component') {
-    let staticName = getAndRemoveAttr(el, 'is')
-    el.component = staticName
-      ? JSON.stringify(staticName)
-      : (getAndRemoveAttr(el, ':is') || getAndRemoveAttr(el, 'v-bind:is'))
+    el.component = getBindingAttr(el, 'is')
   }
 }
 
 function processClassBinding (el) {
   const staticClass = getAndRemoveAttr(el, 'class')
   el.staticClass = parseText(staticClass) || JSON.stringify(staticClass)
-  el.classBinding =
-    getAndRemoveAttr(el, ':class') ||
-    getAndRemoveAttr(el, 'v-bind:class')
+  el.classBinding = getBindingAttr(el, 'class', false /* getStatic */)
 }
 
 function processStyleBinding (el) {
-  el.styleBinding =
-    getAndRemoveAttr(el, ':style') ||
-    getAndRemoveAttr(el, 'v-bind:style')
+  el.styleBinding = getBindingAttr(el, 'style', false /* getStatic */)
 }
 
 function processAttrs (el) {
@@ -339,32 +292,24 @@ function processAttrs (el) {
       if (bindRE.test(name)) { // v-bind
         name = name.replace(bindRE, '')
         if (mustUseProp(name)) {
-          (el.props || (el.props = [])).push({ name, value })
+          addProp(el, name, value)
         } else {
-          (el.attrs || (el.attrs = [])).push({ name, value })
+          addAttr(el, name, value)
         }
       } else if (onRE.test(name)) { // v-on
         name = name.replace(onRE, '')
-        addHandler((el.events || (el.events = {})), name, value, modifiers)
+        addHandler(el, name, value, modifiers)
       } else { // normal directives
         name = name.replace(dirRE, '')
         // parse arg
         if ((arg = name.match(argRE)) && (arg = arg[1])) {
           name = name.slice(0, -(arg.length + 1))
         }
-        ;(el.directives || (el.directives = [])).push({
-          name,
-          value,
-          arg,
-          modifiers
-        })
+        addDirective(el, name, value, arg, modifiers)
       }
     } else {
       // literal attribute
-      (el.attrs || (el.attrs = [])).push({
-        name,
-        value: parseText(value) || JSON.stringify(value)
-      })
+      addAttr(el, name, parseText(value) || JSON.stringify(value))
     }
   }
 }
@@ -389,21 +334,6 @@ function makeAttrsMap (attrs) {
   return map
 }
 
-function getAndRemoveAttr (el, attr) {
-  let val
-  if ((val = el.attrsMap[attr]) != null) {
-    el.attrsMap[attr] = null
-    const list = el.attrsList
-    for (let i = 0, l = list.length; i < l; i++) {
-      if (list[i].name === attr) {
-        list.splice(i, 1)
-        break
-      }
-    }
-  }
-  return val
-}
-
 function findPrevElement (children) {
   let i = children.length
   while (i--) {

+ 6 - 3
src/runtime/instance/proxy.js

@@ -1,8 +1,10 @@
-import { warn } from '../util/index'
+import { warn, inBrowser } from '../util/index'
 
 let hasProxy, proxyHandlers, initProxy
 
 if (process.env.NODE_ENV !== 'production') {
+  let context = inBrowser ? window : global
+
   hasProxy =
     typeof Proxy !== 'undefined' &&
     Proxy.toString().match(/native code/)
@@ -12,13 +14,14 @@ if (process.env.NODE_ENV !== 'production') {
       if (key === 'undefined') {
         return false
       }
-      if (!(key in target)) {
+      let has = key in target
+      if (!has && !(key in context)) {
         warn(
           `Trying to access non-existent property "${key}" while rendering.`,
           target
         )
       }
-      return true
+      return has
     }
   }