|
|
@@ -1,5 +1,5 @@
|
|
|
import Watcher from '../observer/watcher'
|
|
|
-import { extend, query, resolveAsset, hasOwn } from '../util/index'
|
|
|
+import { extend, query, resolveAsset, hasOwn, isArray, isObject } from '../util/index'
|
|
|
import { createElement, patch, updateListeners } from '../vdom/index'
|
|
|
import { callHook } from './lifecycle'
|
|
|
import { getPropValue } from './state'
|
|
|
@@ -18,78 +18,6 @@ export function initRender (vm) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function resolveSlots (vm, children) {
|
|
|
- if (children) {
|
|
|
- children = children.slice()
|
|
|
- const slots = { default: children }
|
|
|
- let i = children.length
|
|
|
- let name, child
|
|
|
- while (i--) {
|
|
|
- child = children[i]
|
|
|
- if ((name = child.data && child.data.slot)) {
|
|
|
- let slot = (slots[name] || (slots[name] = []))
|
|
|
- if (child.tag === 'template') {
|
|
|
- slot.push.apply(slot, child.children)
|
|
|
- } else {
|
|
|
- slot.push(child)
|
|
|
- }
|
|
|
- children.splice(i, 1)
|
|
|
- }
|
|
|
- }
|
|
|
- vm.$slots = slots
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function mergeParentData (vm, data, parentData) {
|
|
|
- const props = vm.$options.props
|
|
|
- if (parentData.attrs) {
|
|
|
- const attrs = data.attrs || (data.attrs = {})
|
|
|
- for (let key in parentData.attrs) {
|
|
|
- if (!hasOwn(props, key)) {
|
|
|
- attrs[key] = parentData.attrs[key]
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (parentData.props) {
|
|
|
- const props = data.props || (data.props = {})
|
|
|
- for (let key in parentData.props) {
|
|
|
- if (!hasOwn(props, key)) {
|
|
|
- props[key] = parentData.props[key]
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (parentData.staticClass) {
|
|
|
- data.staticClass = data.staticClass
|
|
|
- ? data.staticClass + ' ' + parentData.staticClass
|
|
|
- : parentData.staticClass
|
|
|
- }
|
|
|
- if (parentData.class) {
|
|
|
- extend((data.class || (data.class = {})), parentData.class)
|
|
|
- }
|
|
|
- if (parentData.style) {
|
|
|
- extend((data.style || (data.style = {})), parentData.style)
|
|
|
- }
|
|
|
- if (parentData.directives) {
|
|
|
- data.directives = parentData.directives.conact(data.directives || [])
|
|
|
- }
|
|
|
- if (parentData.on) {
|
|
|
- updateListeners(parentData.on, data.on || {}, (event, handler) => {
|
|
|
- vm.$on(event, handler)
|
|
|
- })
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function updateProps (vm, data) {
|
|
|
- if (data.attrs || data.props) {
|
|
|
- for (let key in vm.$options.props) {
|
|
|
- let newVal = getPropValue(data, key)
|
|
|
- if (vm[key] !== newVal) {
|
|
|
- vm[key] = newVal
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
export function renderMixin (Vue) {
|
|
|
// shorthands used in render functions
|
|
|
Vue.prototype.__h__ = createElement
|
|
|
@@ -112,21 +40,21 @@ export function renderMixin (Vue) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- Vue.prototype._tryUpdate = function (data, children, key) {
|
|
|
+ Vue.prototype._tryUpdate = function (parentData, children, key) {
|
|
|
+ const oldParentData = this.$options._renderData
|
|
|
this.$options._renderKey = key
|
|
|
- this.$options._renderData = data
|
|
|
+ this.$options._renderData = parentData
|
|
|
this.$options._renderChildren = children
|
|
|
- // set props - this will trigger update if any of them changed
|
|
|
- // but not guaranteed
|
|
|
- if (data) {
|
|
|
- updateProps(this, data)
|
|
|
+ // update props and listeners
|
|
|
+ if (parentData) {
|
|
|
+ updateProps(this, parentData)
|
|
|
+ updateEvents(this, parentData)
|
|
|
}
|
|
|
// for now, if the component has content it always updates
|
|
|
// because we don't know whether the children have changed.
|
|
|
// need to optimize in the future.
|
|
|
- if (children) {
|
|
|
+ if (children || diffParentData(parentData, oldParentData)) {
|
|
|
this.$forceUpdate()
|
|
|
- return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -172,3 +100,113 @@ export function renderMixin (Vue) {
|
|
|
this._watcher.update()
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+function resolveSlots (vm, children) {
|
|
|
+ if (children) {
|
|
|
+ children = children.slice()
|
|
|
+ const slots = { default: children }
|
|
|
+ let i = children.length
|
|
|
+ let name, child
|
|
|
+ while (i--) {
|
|
|
+ child = children[i]
|
|
|
+ if ((name = child.data && child.data.slot)) {
|
|
|
+ let slot = (slots[name] || (slots[name] = []))
|
|
|
+ if (child.tag === 'template') {
|
|
|
+ slot.push.apply(slot, child.children)
|
|
|
+ } else {
|
|
|
+ slot.push(child)
|
|
|
+ }
|
|
|
+ children.splice(i, 1)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ vm.$slots = slots
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function diffParentData (data, oldData) {
|
|
|
+ let key, old, cur
|
|
|
+ for (key in oldData) {
|
|
|
+ cur = data[key]
|
|
|
+ old = oldData[key]
|
|
|
+ if (key === 'on') continue
|
|
|
+ if (!cur) return true
|
|
|
+ if (isArray(old)) {
|
|
|
+ if (!isArray(cur)) return true
|
|
|
+ if (cur.length !== old.length) return true
|
|
|
+ for (let i = 0; i < old.length; i++) {
|
|
|
+ if (isObject(old[i])) {
|
|
|
+ if (!isObject(cur[i])) return true
|
|
|
+ if (diffObject(cur, old)) return true
|
|
|
+ } else if (old[i] !== cur[i]) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (diffObject(cur, old)) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function diffObject (cur, old) {
|
|
|
+ for (var key in old) {
|
|
|
+ if (cur[key] !== old[key]) return true
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function mergeParentData (vm, data, parentData) {
|
|
|
+ const props = vm.$options.props
|
|
|
+ if (parentData.attrs) {
|
|
|
+ const attrs = data.attrs || (data.attrs = {})
|
|
|
+ for (let key in parentData.attrs) {
|
|
|
+ if (!hasOwn(props, key)) {
|
|
|
+ attrs[key] = parentData.attrs[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (parentData.props) {
|
|
|
+ const props = data.props || (data.props = {})
|
|
|
+ for (let key in parentData.props) {
|
|
|
+ if (!hasOwn(props, key)) {
|
|
|
+ props[key] = parentData.props[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (parentData.staticClass) {
|
|
|
+ data.staticClass = data.staticClass
|
|
|
+ ? data.staticClass + ' ' + parentData.staticClass
|
|
|
+ : parentData.staticClass
|
|
|
+ }
|
|
|
+ if (parentData.class) {
|
|
|
+ if (!data.class) {
|
|
|
+ data.class = parentData.class
|
|
|
+ } else {
|
|
|
+ data.class = (isArray(data.class) ? data.class : []).concat(parentData.class)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (parentData.style) {
|
|
|
+ if (!data.style) {
|
|
|
+ data.style = parentData.style
|
|
|
+ } else {
|
|
|
+ extend(data.style, parentData.style)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (parentData.directives) {
|
|
|
+ data.directives = parentData.directives.conact(data.directives || [])
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function updateProps (vm, data) {
|
|
|
+ if (data.attrs || data.props) {
|
|
|
+ for (let key in vm.$options.props) {
|
|
|
+ vm[key] = getPropValue(data, key)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function updateEvents (vm, data) {
|
|
|
+ if (data.on) {
|
|
|
+ updateListeners(data.on, vm._vnode.data.on || {}, (event, handler) => {
|
|
|
+ vm.$on(event, handler)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|