| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- import { EMPTY_OBJ, NOOP } from '@vue/shared'
- import { VNode, Slots, RenderNode, MountedVNode } from './vdom'
- import {
- Data,
- ComponentOptions,
- ComponentClassOptions,
- ComponentPropsOptions,
- WatchOptions
- } from './componentOptions'
- import { setupWatcher } from './componentWatch'
- import { Autorun, DebuggerEvent, ComputedGetter } from '@vue/observer'
- import { nextTick } from '@vue/scheduler'
- import { ErrorTypes } from './errorHandling'
- import { initializeComponentInstance } from './componentUtils'
- import { EventEmitter, invokeListeners } from './optional/eventEmitter'
- import { warn } from './warning'
- // public component instance type
- export interface Component<P = {}, D = {}> extends PublicInstanceMethods {
- readonly $el: any
- readonly $vnode: MountedVNode
- readonly $parentVNode: MountedVNode
- readonly $data: D
- readonly $props: Readonly<P>
- readonly $attrs: Readonly<Data>
- readonly $slots: Slots
- readonly $root: Component
- readonly $parent: Component
- readonly $children: Component[]
- readonly $options: ComponentOptions<P, D, this>
- readonly $refs: Record<string | symbol, any>
- readonly $proxy: this
- }
- interface PublicInstanceMethods {
- $forceUpdate(): void
- $nextTick(fn: () => any): Promise<void>
- $watch(
- keyOrFn: string | ((this: this) => any),
- cb: (this: this, newValue: any, oldValue: any) => void,
- options?: WatchOptions
- ): () => void
- $emit(name: string, ...payload: any[]): void
- }
- export interface APIMethods<P = {}, D = {}> {
- data(): Partial<D>
- hooks(): any
- render(props: Readonly<P>, slots: Slots, attrs: Data, parentVNode: VNode): any
- }
- export interface LifecycleMethods {
- beforeCreate(): void
- created(): void
- beforeMount(): void
- mounted(): void
- beforeUpdate(vnode: VNode): void
- updated(vnode: VNode): void
- beforeUnmount(): void
- unmounted(): void
- errorCaptured(): (
- err: Error,
- type: ErrorTypes,
- instance: ComponentInstance | null,
- vnode: VNode
- ) => boolean | void
- activated(): void
- deactivated(): void
- renderTracked(e: DebuggerEvent): void
- renderTriggered(e: DebuggerEvent): void
- }
- export interface ComponentClass extends ComponentClassOptions {
- options?: ComponentOptions
- new <P = {}, D = {}>(): Component<P, D> & D & P
- }
- export interface FunctionalComponent<P = {}> {
- (props: P, slots: Slots, attrs: Data, parentVNode: VNode): any
- pure?: boolean
- props?: ComponentPropsOptions<P>
- displayName?: string
- }
- export type ComponentType = ComponentClass | FunctionalComponent
- // Internal type that represents a mounted instance.
- // It extends InternalComponent with mounted instance properties.
- export interface ComponentInstance<P = {}, D = {}>
- extends InternalComponent,
- Partial<APIMethods<P, D>>,
- Partial<LifecycleMethods> {
- constructor: ComponentClass
- render: APIMethods<P, D>['render']
- $vnode: MountedVNode
- $data: D
- $props: P
- $attrs: Data
- $slots: Slots
- $root: ComponentInstance
- $children: ComponentInstance[]
- $options: ComponentOptions<P, D>
- _updateHandle: Autorun
- _queueJob: ((fn: () => void) => void)
- _self: ComponentInstance<P, D> // on proxies only
- }
- // actual implementation of the component
- class InternalComponent implements PublicInstanceMethods {
- get $el(): any {
- return this.$vnode && this.$vnode.el
- }
- $vnode: VNode | null = null
- $parentVNode: VNode | null = null
- $data: Data | null = null
- $props: Data | null = null
- $attrs: Data | null = null
- $slots: Slots | null = null
- $root: ComponentInstance | null = null
- $parent: ComponentInstance | null = null
- $children: ComponentInstance[] = []
- $options: ComponentOptions | null = null
- $refs: Record<string, ComponentInstance | RenderNode> = {}
- $proxy: any = null
- _rawData: Data | null = null
- _computedGetters: Record<string, ComputedGetter> | null = null
- _watchHandles: Set<Autorun> | null = null
- _mounted: boolean = false
- _unmounted: boolean = false
- _events: { [event: string]: Function[] | null } | null = null
- _updateHandle: Autorun | null = null
- _queueJob: ((fn: () => void) => void) | null = null
- _isVue: boolean = true
- _inactiveRoot: boolean = false
- _hookProps: any = null
- constructor(props?: object) {
- if (props === void 0) {
- initializeComponentInstance(this as any)
- } else {
- // the presence of the props argument indicates that this class is being
- // instantiated as a mixin, and should expose the props on itself
- // so that the extended class constructor (and property initializers) can
- // access $props.
- this.$props = props
- }
- if (__COMPAT__) {
- ;(this as any)._eventEmitter = new EventEmitter(this)
- }
- }
- // necessary to tell this apart from a functional
- render(...args: any[]): any {
- if (__DEV__) {
- const name =
- (this.$options && this.$options.displayName) || this.constructor.name
- warn(`Class component \`${name}\` is missing render() method.`)
- }
- }
- // to be set by renderer during mount
- $forceUpdate: () => void = NOOP
- $nextTick(fn: () => any): Promise<void> {
- return nextTick(fn)
- }
- $watch(
- keyOrFn: string | ((this: this) => any),
- cb: (this: this, newValue: any, oldValue: any) => void,
- options?: WatchOptions
- ): () => void {
- return setupWatcher(this as any, keyOrFn, cb, options)
- }
- $emit(name: string, ...payload: any[]) {
- const parentData =
- (this.$parentVNode && this.$parentVNode.data) || EMPTY_OBJ
- const parentListener =
- parentData['on' + name] || parentData['on' + name.toLowerCase()]
- if (parentListener) {
- invokeListeners(parentListener, payload)
- }
- }
- }
- // legacy event emitter interface exposed on component instances
- if (__COMPAT__) {
- const p = InternalComponent.prototype as any
- ;['on', 'off', 'once'].forEach(key => {
- p['$' + key] = function(...args: any[]) {
- this._eventEmitter[key](...args)
- return this
- }
- })
- const emit = p.$emit
- p.$emit = function(...args: any[]) {
- emit.call(this, ...args)
- this._eventEmitter.emit(...args)
- return this
- }
- }
- // the exported Component has the implementation details of the actual
- // InternalComponent class but with proper type inference of ComponentClass.
- export const Component = InternalComponent as ComponentClass
|