aboutsummaryrefslogtreecommitdiff
path: root/node_modules/vue/src/core/instance/lifecycle.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/vue/src/core/instance/lifecycle.js')
-rw-r--r--node_modules/vue/src/core/instance/lifecycle.js336
1 files changed, 336 insertions, 0 deletions
diff --git a/node_modules/vue/src/core/instance/lifecycle.js b/node_modules/vue/src/core/instance/lifecycle.js
new file mode 100644
index 00000000..169a54a6
--- /dev/null
+++ b/node_modules/vue/src/core/instance/lifecycle.js
@@ -0,0 +1,336 @@
+/* @flow */
+
+import config from '../config'
+import Watcher from '../observer/watcher'
+import { mark, measure } from '../util/perf'
+import { createEmptyVNode } from '../vdom/vnode'
+import { updateComponentListeners } from './events'
+import { resolveSlots } from './render-helpers/resolve-slots'
+import { toggleObserving } from '../observer/index'
+import { pushTarget, popTarget } from '../observer/dep'
+
+import {
+ warn,
+ noop,
+ remove,
+ handleError,
+ emptyObject,
+ validateProp
+} from '../util/index'
+
+export let activeInstance: any = null
+export let isUpdatingChildComponent: boolean = false
+
+export function initLifecycle (vm: Component) {
+ const options = vm.$options
+
+ // locate first non-abstract parent
+ let parent = options.parent
+ if (parent && !options.abstract) {
+ while (parent.$options.abstract && parent.$parent) {
+ parent = parent.$parent
+ }
+ parent.$children.push(vm)
+ }
+
+ vm.$parent = parent
+ vm.$root = parent ? parent.$root : vm
+
+ vm.$children = []
+ vm.$refs = {}
+
+ vm._watcher = null
+ vm._inactive = null
+ vm._directInactive = false
+ vm._isMounted = false
+ vm._isDestroyed = false
+ vm._isBeingDestroyed = false
+}
+
+export function lifecycleMixin (Vue: Class<Component>) {
+ Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
+ const vm: Component = this
+ if (vm._isMounted) {
+ callHook(vm, 'beforeUpdate')
+ }
+ const prevEl = vm.$el
+ const prevVnode = vm._vnode
+ const prevActiveInstance = activeInstance
+ activeInstance = vm
+ vm._vnode = vnode
+ // Vue.prototype.__patch__ is injected in entry points
+ // based on the rendering backend used.
+ if (!prevVnode) {
+ // initial render
+ vm.$el = vm.__patch__(
+ vm.$el, vnode, hydrating, false /* removeOnly */,
+ vm.$options._parentElm,
+ vm.$options._refElm
+ )
+ // no need for the ref nodes after initial patch
+ // this prevents keeping a detached DOM tree in memory (#5851)
+ vm.$options._parentElm = vm.$options._refElm = null
+ } else {
+ // updates
+ vm.$el = vm.__patch__(prevVnode, vnode)
+ }
+ activeInstance = prevActiveInstance
+ // update __vue__ reference
+ if (prevEl) {
+ prevEl.__vue__ = null
+ }
+ if (vm.$el) {
+ vm.$el.__vue__ = vm
+ }
+ // if parent is an HOC, update its $el as well
+ if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
+ vm.$parent.$el = vm.$el
+ }
+ // updated hook is called by the scheduler to ensure that children are
+ // updated in a parent's updated hook.
+ }
+
+ Vue.prototype.$forceUpdate = function () {
+ const vm: Component = this
+ if (vm._watcher) {
+ vm._watcher.update()
+ }
+ }
+
+ Vue.prototype.$destroy = function () {
+ const vm: Component = this
+ if (vm._isBeingDestroyed) {
+ return
+ }
+ callHook(vm, 'beforeDestroy')
+ vm._isBeingDestroyed = true
+ // remove self from parent
+ const parent = vm.$parent
+ if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
+ remove(parent.$children, vm)
+ }
+ // teardown watchers
+ if (vm._watcher) {
+ vm._watcher.teardown()
+ }
+ let i = vm._watchers.length
+ while (i--) {
+ vm._watchers[i].teardown()
+ }
+ // remove reference from data ob
+ // frozen object may not have observer.
+ if (vm._data.__ob__) {
+ vm._data.__ob__.vmCount--
+ }
+ // call the last hook...
+ vm._isDestroyed = true
+ // invoke destroy hooks on current rendered tree
+ vm.__patch__(vm._vnode, null)
+ // fire destroyed hook
+ callHook(vm, 'destroyed')
+ // turn off all instance listeners.
+ vm.$off()
+ // remove __vue__ reference
+ if (vm.$el) {
+ vm.$el.__vue__ = null
+ }
+ // release circular reference (#6759)
+ if (vm.$vnode) {
+ vm.$vnode.parent = null
+ }
+ }
+}
+
+export function mountComponent (
+ vm: Component,
+ el: ?Element,
+ hydrating?: boolean
+): Component {
+ vm.$el = el
+ if (!vm.$options.render) {
+ vm.$options.render = createEmptyVNode
+ if (process.env.NODE_ENV !== 'production') {
+ /* istanbul ignore if */
+ if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
+ vm.$options.el || el) {
+ warn(
+ 'You are using the runtime-only build of Vue where the template ' +
+ 'compiler is not available. Either pre-compile the templates into ' +
+ 'render functions, or use the compiler-included build.',
+ vm
+ )
+ } else {
+ warn(
+ 'Failed to mount component: template or render function not defined.',
+ vm
+ )
+ }
+ }
+ }
+ callHook(vm, 'beforeMount')
+
+ let updateComponent
+ /* istanbul ignore if */
+ if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
+ updateComponent = () => {
+ const name = vm._name
+ const id = vm._uid
+ const startTag = `vue-perf-start:${id}`
+ const endTag = `vue-perf-end:${id}`
+
+ mark(startTag)
+ const vnode = vm._render()
+ mark(endTag)
+ measure(`vue ${name} render`, startTag, endTag)
+
+ mark(startTag)
+ vm._update(vnode, hydrating)
+ mark(endTag)
+ measure(`vue ${name} patch`, startTag, endTag)
+ }
+ } else {
+ updateComponent = () => {
+ vm._update(vm._render(), hydrating)
+ }
+ }
+
+ // we set this to vm._watcher inside the watcher's constructor
+ // since the watcher's initial patch may call $forceUpdate (e.g. inside child
+ // component's mounted hook), which relies on vm._watcher being already defined
+ new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)
+ hydrating = false
+
+ // manually mounted instance, call mounted on self
+ // mounted is called for render-created child components in its inserted hook
+ if (vm.$vnode == null) {
+ vm._isMounted = true
+ callHook(vm, 'mounted')
+ }
+ return vm
+}
+
+export function updateChildComponent (
+ vm: Component,
+ propsData: ?Object,
+ listeners: ?Object,
+ parentVnode: MountedComponentVNode,
+ renderChildren: ?Array<VNode>
+) {
+ if (process.env.NODE_ENV !== 'production') {
+ isUpdatingChildComponent = true
+ }
+
+ // determine whether component has slot children
+ // we need to do this before overwriting $options._renderChildren
+ const hasChildren = !!(
+ renderChildren || // has new static slots
+ vm.$options._renderChildren || // has old static slots
+ parentVnode.data.scopedSlots || // has new scoped slots
+ vm.$scopedSlots !== emptyObject // has old scoped slots
+ )
+
+ vm.$options._parentVnode = parentVnode
+ vm.$vnode = parentVnode // update vm's placeholder node without re-render
+
+ if (vm._vnode) { // update child tree's parent
+ vm._vnode.parent = parentVnode
+ }
+ vm.$options._renderChildren = renderChildren
+
+ // update $attrs and $listeners hash
+ // these are also reactive so they may trigger child update if the child
+ // used them during render
+ vm.$attrs = parentVnode.data.attrs || emptyObject
+ vm.$listeners = listeners || emptyObject
+
+ // update props
+ if (propsData && vm.$options.props) {
+ toggleObserving(false)
+ const props = vm._props
+ const propKeys = vm.$options._propKeys || []
+ for (let i = 0; i < propKeys.length; i++) {
+ const key = propKeys[i]
+ const propOptions: any = vm.$options.props // wtf flow?
+ props[key] = validateProp(key, propOptions, propsData, vm)
+ }
+ toggleObserving(true)
+ // keep a copy of raw propsData
+ vm.$options.propsData = propsData
+ }
+
+ // update listeners
+ listeners = listeners || emptyObject
+ const oldListeners = vm.$options._parentListeners
+ vm.$options._parentListeners = listeners
+ updateComponentListeners(vm, listeners, oldListeners)
+
+ // resolve slots + force update if has children
+ if (hasChildren) {
+ vm.$slots = resolveSlots(renderChildren, parentVnode.context)
+ vm.$forceUpdate()
+ }
+
+ if (process.env.NODE_ENV !== 'production') {
+ isUpdatingChildComponent = false
+ }
+}
+
+function isInInactiveTree (vm) {
+ while (vm && (vm = vm.$parent)) {
+ if (vm._inactive) return true
+ }
+ return false
+}
+
+export function activateChildComponent (vm: Component, direct?: boolean) {
+ if (direct) {
+ vm._directInactive = false
+ if (isInInactiveTree(vm)) {
+ return
+ }
+ } else if (vm._directInactive) {
+ return
+ }
+ if (vm._inactive || vm._inactive === null) {
+ vm._inactive = false
+ for (let i = 0; i < vm.$children.length; i++) {
+ activateChildComponent(vm.$children[i])
+ }
+ callHook(vm, 'activated')
+ }
+}
+
+export function deactivateChildComponent (vm: Component, direct?: boolean) {
+ if (direct) {
+ vm._directInactive = true
+ if (isInInactiveTree(vm)) {
+ return
+ }
+ }
+ if (!vm._inactive) {
+ vm._inactive = true
+ for (let i = 0; i < vm.$children.length; i++) {
+ deactivateChildComponent(vm.$children[i])
+ }
+ callHook(vm, 'deactivated')
+ }
+}
+
+export function callHook (vm: Component, hook: string) {
+ // #7573 disable dep collection when invoking lifecycle hooks
+ pushTarget()
+ const handlers = vm.$options[hook]
+ if (handlers) {
+ for (let i = 0, j = handlers.length; i < j; i++) {
+ try {
+ handlers[i].call(vm)
+ } catch (e) {
+ handleError(e, vm, `${hook} hook`)
+ }
+ }
+ }
+ if (vm._hasHookEvent) {
+ vm.$emit('hook:' + hook)
+ }
+ popTarget()
+}