import {
+ Component,
ComponentInstance,
ComponentClass,
APIMethods,
// This is called in the base component constructor and the return value is
// set on the instance as $options.
export function resolveComponentOptionsFromClass(
- Component: ComponentClass
+ Class: ComponentClass
): ComponentOptions {
- if (Component.options) {
- return Component.options
+ if (Class.hasOwnProperty('options')) {
+ return Class.options as ComponentOptions
}
- const staticDescriptors = Object.getOwnPropertyDescriptors(Component)
- const options = {} as any
+ let options = {} as any
+
+ const staticDescriptors = Object.getOwnPropertyDescriptors(Class)
for (const key in staticDescriptors) {
const { enumerable, get, value } = staticDescriptors[key]
if (enumerable || get) {
options[key] = get ? get() : value
}
}
- const instanceDescriptors = Object.getOwnPropertyDescriptors(
- Component.prototype
- )
+
+ const instanceDescriptors = Object.getOwnPropertyDescriptors(Class.prototype)
for (const key in instanceDescriptors) {
const { get, value } = instanceDescriptors[key]
if (get) {
;(options.computed || (options.computed = {}))[key] = get
// there's no need to do anything for the setter
// as it's already defined on the prototype
- } else if (isFunction(value)) {
+ } else if (isFunction(value) && key !== 'constructor') {
if (key in reservedMethods) {
options[key] = value
} else {
}
}
}
+
options.props = normalizePropsOptions(options.props)
- Component.options = options
+
+ const ParentClass = Object.getPrototypeOf(Class)
+ if (ParentClass !== Component) {
+ const parentOptions = resolveComponentOptionsFromClass(ParentClass)
+ options = mergeComponentOptions(parentOptions, options)
+ }
+
+ Class.options = options
return options
}
if (key === 'data') {
// for data we need to merge the returned value
res[key] = function() {
- return Object.assign(existing(), value())
+ return Object.assign(existing.call(this), value.call(this))
}
} else if (/^render|^errorCaptured/.test(key)) {
// render, renderTracked, renderTriggered & errorCaptured
currentVNode = vnode
currentContextVNode = vnode.contextVNode
const instance = (vnode.children = new Component() as ComponentInstance)
+
// then we finish the initialization by collecting properties set on the
// instance
+ const {
+ $proxy,
+ $options: { created, computed, watch }
+ } = instance
initializeState(instance)
- initializeComputed(instance, instance.$options.computed)
- initializeWatch(instance, instance.$options.watch)
+ initializeComputed(instance, computed)
+ initializeWatch(instance, watch)
instance.$slots = currentVNode.slots || EMPTY_OBJ
- if (instance.created) {
- instance.created.call(instance.$proxy)
+
+ if (created) {
+ created.call($proxy)
}
+
currentVNode = currentContextVNode = null
return instance
}
}
// beforeCreate hook is called right in the constructor
- if (instance.beforeCreate) {
- instance.beforeCreate.call(proxy)
+ const { beforeCreate, props } = instance.$options
+ if (beforeCreate) {
+ beforeCreate.call(proxy)
}
- initializeProps(
- instance,
- instance.$options.props,
- (currentVNode as VNode).data
- )
+ initializeProps(instance, props, (currentVNode as VNode).data)
}
export function renderInstanceRoot(instance: ComponentInstance): VNode {
;(instance as any).$unmount = unmountComponentInstance
}
- if (instance.beforeMount) {
- instance.beforeMount.call(instance.$proxy)
+ const {
+ $proxy,
+ $options: { beforeMount, mounted, renderTracked, renderTriggered }
+ } = instance
+
+ if (beforeMount) {
+ beforeMount.call($proxy)
}
const queueUpdate = (instance.$forceUpdate = () => {
}
instance._mounted = true
- mountComponentInstanceCallbacks(instance, vnode.ref)
+ if (vnode.ref) {
+ mountRef(vnode.ref, $proxy)
+ }
+ if (mounted) {
+ lifecycleHooks.push(() => {
+ mounted.call($proxy)
+ })
+ }
}
},
{
scheduler: queueUpdate,
- onTrack: instance.renderTracked,
- onTrigger: instance.renderTriggered
+ onTrack: renderTracked,
+ onTrigger: renderTriggered
}
)
return vnode.el as RenderNode
}
- function mountComponentInstanceCallbacks(
- instance: ComponentInstance,
- ref: Ref | null
- ) {
- if (ref) {
- mountRef(ref, instance.$proxy)
- }
- if (instance.mounted) {
- lifecycleHooks.push(() => {
- ;(instance as any).mounted.call(instance.$proxy)
- })
- }
- }
-
function updateComponentInstance(
instance: ComponentInstance,
isSVG: boolean
if (__DEV__ && instance.$parentVNode) {
pushWarningContext(instance.$parentVNode as VNode)
}
- const prevVNode = instance.$vnode
- if (instance.beforeUpdate) {
- instance.beforeUpdate.call(instance.$proxy, prevVNode)
+ const {
+ $vnode: prevVNode,
+ $parentVNode,
+ $proxy,
+ $options: { beforeUpdate, updated }
+ } = instance
+ if (beforeUpdate) {
+ beforeUpdate.call($proxy, prevVNode)
}
const nextVNode = (instance.$vnode = renderInstanceRoot(
instance
) as MountedVNode)
const container = platformParentNode(prevVNode.el) as RenderNode
- patch(
- prevVNode,
- nextVNode,
- container,
- instance.$parentVNode as MountedVNode,
- isSVG
- )
+ patch(prevVNode, nextVNode, container, $parentVNode as MountedVNode, isSVG)
const el = nextVNode.el as RenderNode
if (__COMPAT__) {
// recursively update contextVNode el for nested HOCs
if ((nextVNode.flags & VNodeFlags.PORTAL) === 0) {
- let vnode = instance.$parentVNode
+ let vnode = $parentVNode
while (vnode !== null) {
if ((vnode.flags & VNodeFlags.COMPONENT) > 0) {
vnode.el = el
}
}
- if (instance.updated) {
+ if (updated) {
// Because the child's update is executed by the scheduler and not
// synchronously within the parent's update call, the child's updated hook
// will be added to the queue AFTER the parent's, but they should be
// invoked BEFORE the parent's. Therefore we add them to the head of the
// queue instead.
lifecycleHooks.unshift(() => {
- ;(instance as any).updated.call(instance.$proxy, nextVNode)
+ updated.call($proxy, nextVNode)
})
}
if (instance._unmounted) {
return
}
- if (instance.beforeUnmount) {
- instance.beforeUnmount.call(instance.$proxy)
- }
- if (instance.$vnode) {
- unmount(instance.$vnode)
- }
- stop(instance._updateHandle)
+ const {
+ $vnode,
+ $proxy,
+ _updateHandle,
+ $options: { beforeUnmount, unmounted }
+ } = instance
+ if (beforeUnmount) {
+ beforeUnmount.call($proxy)
+ }
+ if ($vnode) {
+ unmount($vnode)
+ }
+ stop(_updateHandle)
teardownComponentInstance(instance)
instance._unmounted = true
- if (instance.unmounted) {
- instance.unmounted.call(instance.$proxy)
+ if (unmounted) {
+ unmounted.call($proxy)
}
}
}
if (asRoot || !instance._inactiveRoot) {
// 2. recursively call activated on child tree, depth-first
- const { $children } = instance
+ const {
+ $children,
+ $proxy,
+ $options: { activated }
+ } = instance
for (let i = 0; i < $children.length; i++) {
callActivatedHook($children[i], false)
}
- if (instance.activated) {
- instance.activated.call(instance.$proxy)
+ if (activated) {
+ activated.call($proxy)
}
}
}
}
if (asRoot || !instance._inactiveRoot) {
// 2. recursively call deactivated on child tree, depth-first
- const { $children } = instance
+ const {
+ $children,
+ $proxy,
+ $options: { deactivated }
+ } = instance
for (let i = 0; i < $children.length; i++) {
callDeactivateHook($children[i], false)
}
- if (instance.deactivated) {
- instance.deactivated.call(instance.$proxy)
+ if (deactivated) {
+ deactivated.call($proxy)
}
}
}