Ver Fonte

convert default props

Evan You há 10 anos atrás
pai
commit
d6bef79575

+ 6 - 4
src/runtime-with-compiler.js

@@ -26,12 +26,14 @@ Vue.prototype.$mount = function (el) {
       } else {
         warn('invalid template option:' + template, this)
       }
-    } else {
+    } else if (el) {
       template = getOuterHTML(query(el))
     }
-    options.render = new Function(compile(template, {
-      preserveWhitespace: config.preserveWhitespace
-    }))
+    if (template) {
+      options.render = new Function(compile(template, {
+        preserveWhitespace: config.preserveWhitespace
+      }))
+    }
   }
   mount.call(this, el)
 }

+ 9 - 1
src/runtime/instance/lifecycle.js

@@ -1,5 +1,5 @@
 import Watcher from '../observer/watcher'
-import { query, toArray } from '../util/index'
+import { query, toArray, warn } from '../util/index'
 
 export function initLifecycle (vm) {
   const options = vm.$options
@@ -19,6 +19,14 @@ export function initLifecycle (vm) {
 
 export function lifecycleMixin (Vue) {
   Vue.prototype.$mount = function (el) {
+    if (!this.$options.render) {
+      this.$options.render = () => this.$createElement('div')
+      process.env.NODE_ENV !== 'production' && warn(
+        'Failed to mount component: ' +
+        'template or render function not defined.',
+        this
+      )
+    }
     callHook(this, 'beforeMount')
     el = this.$el = el && query(el)
     if (el) {

+ 5 - 2
src/runtime/instance/render.js

@@ -1,4 +1,5 @@
 import { callHook } from './lifecycle'
+import { observerState } from '../observer/index'
 import {
   createElement,
   patch,
@@ -197,7 +198,7 @@ function mergeParentData (vm, data, parentData) {
   if (parentData.attrs) {
     const attrs = data.attrs || (data.attrs = {})
     for (let key in parentData.attrs) {
-      if (!props[key]) {
+      if (!props || !props[key]) {
         attrs[key] = parentData.attrs[key]
       }
     }
@@ -205,7 +206,7 @@ function mergeParentData (vm, data, parentData) {
   if (parentData.props) {
     const props = data.props || (data.props = {})
     for (let key in parentData.props) {
-      if (!props[key]) {
+      if (!props || !props[key]) {
         props[key] = parentData.props[key]
       }
     }
@@ -239,6 +240,7 @@ function updateProps (vm, data) {
   if (data.attrs || data.props) {
     let keys = vm.$options.propKeys
     if (keys) {
+      observerState.shouldConvert = false
       for (let i = 0; i < keys.length; i++) {
         let key = keys[i]
         let oldVal = vm[key]
@@ -248,6 +250,7 @@ function updateProps (vm, data) {
           changed = true
         }
       }
+      observerState.shouldConvert = true
     }
   }
   return changed

+ 7 - 7
src/runtime/instance/state.js

@@ -3,7 +3,7 @@ import Dep from '../observer/dep'
 import {
   observe,
   defineReactive,
-  withoutConversion
+  observerState
 } from '../observer/index'
 import {
   warn,
@@ -28,12 +28,12 @@ function initProps (vm) {
   const props = vm.$options.props
   if (props) {
     const keys = vm.$options.propKeys = Object.keys(props)
-    withoutConversion(() => {
-      for (let i = 0; i < keys.length; i++) {
-        let key = keys[i]
-        defineReactive(vm, key, getPropValue(data, key, vm))
-      }
-    })
+    observerState.shouldConvert = false
+    for (let i = 0; i < keys.length; i++) {
+      let key = keys[i]
+      defineReactive(vm, key, getPropValue(data, key, vm))
+    }
+    observerState.shouldConvert = true
   }
 }
 

+ 7 - 16
src/runtime/observer/index.js

@@ -13,19 +13,13 @@ const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
 
 /**
  * By default, when a reactive property is set, the new value is
- * also converted to become reactive. However in certain cases, e.g.
- * v-for scope alias and props, we don't want to force conversion
- * because the value may be a nested value under a frozen data structure.
- *
- * So whenever we want to set a reactive property without forcing
- * conversion on the new value, we wrap that call inside this function.
+ * also converted to become reactive. However when passing down props,
+ * we don't want to force conversion because the value may be a nested value
+ * under a frozen data structure. Converting it would defeat the optimization.
  */
 
-let shouldConvert = true
-export function withoutConversion (fn) {
-  shouldConvert = false
-  fn()
-  shouldConvert = true
+export const observerState = {
+  shouldConvert: true
 }
 
 /**
@@ -165,13 +159,10 @@ export function observe (value, vm) {
     return
   }
   var ob
-  if (
-    hasOwn(value, '__ob__') &&
-    value.__ob__ instanceof Observer
-  ) {
+  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
     ob = value.__ob__
   } else if (
-    shouldConvert &&
+    observerState.shouldConvert &&
     (isArray(value) || isPlainObject(value)) &&
     Object.isExtensible(value) &&
     !value._isVue

+ 33 - 15
src/runtime/util/props.js

@@ -1,32 +1,41 @@
 import { hyphenate, hasOwn, isArray, isObject, isPlainObject } from './lang'
+import { observe, observerState } from '../observer/index'
 import { warn } from './debug'
 
 export function getPropValue (data, key, vm) {
   if (!data) return
   const prop = vm.$options.props[key]
   const altKey = hyphenate(key)
-  const attrVal = getPropValueFromHash(data.attrs, key, altKey)
-  let value = attrVal === undefined
-    ? getPropValueFromHash(data.props, key, altKey)
-    : attrVal
+  const props = data.props
+  const attrs = data.attrs
+  let value
+  let absent = false
+  if (attrs && hasOwn(attrs, key)) {
+    value = attrs[key]
+  } else if (attrs && hasOwn(attrs, altKey)) {
+    value = attrs[altKey]
+  } else if (props && hasOwn(props, key)) {
+    value = props[key]
+  } else if (props && hasOwn(props, altKey)) {
+    value = props[altKey]
+  } else {
+    absent = true
+  }
   // check default value
   if (value === undefined) {
     value = getPropDefaultValue(vm, prop, key)
+    // since the default value is a fresh copy,
+    // make sure to observe it.
+    observerState.shouldConvert = true
+    observe(value)
+    observerState.shouldConvert = false
   }
   if (process.env.NODE_ENV !== 'production') {
-    assertProp(prop, key, value, vm)
+    assertProp(prop, key, value, vm, absent)
   }
   return value
 }
 
-function getPropValueFromHash (hash, key, altKey) {
-  return hash
-    ? hasOwn(hash, key)
-      ? hash[key]
-      : hash[altKey]
-    : undefined
-}
-
 /**
  * Get the default value of a prop.
  *
@@ -63,14 +72,23 @@ function getPropDefaultValue (vm, prop, name) {
  * Assert whether a prop is valid.
  *
  * @param {Object} prop
+ * @param {String} name
  * @param {*} value
  * @param {Vue} vm
+ * @param {Boolean} absent
  */
 
-function assertProp (prop, name, value, vm) {
-  if (prop.required && value == null) {
+function assertProp (prop, name, value, vm, absent) {
+  if (prop.required && absent) {
+    process.env.NODE_ENV !== 'production' && warn(
+      'Missing required prop: "' + name + '"',
+      vm
+    )
     return false
   }
+  if (value == null) {
+    return true
+  }
   var type = prop.type
   var valid = !type
   var expectedTypes = []