Browse Source

annotate Vue class

dev
Evan You 9 years ago
parent
commit
354ea616b5
  1. 1
      .flowconfig
  2. 10
      flow/declarations.js
  3. 2
      src/compiler/directives/ref.js
  4. 26
      src/core/config.js
  5. 7
      src/core/index.js
  6. 38
      src/core/instance/events.js
  7. 98
      src/core/instance/index.js
  8. 29
      src/core/instance/lifecycle.js
  9. 2
      src/core/instance/proxy.js
  10. 45
      src/core/instance/render.js
  11. 6
      src/core/instance/state.js
  12. 2
      src/core/vdom/create-component.js
  13. 4
      src/core/vdom/create-element.js
  14. 6
      src/core/vdom/helpers.js
  15. 4
      src/core/vdom/patch.js
  16. 33
      src/core/vdom/vnode.js
  17. 2
      src/platforms/web/runtime/modules/transition.js
  18. 3
      src/server/create-renderer.js
  19. 2
      src/server/render.js

1
.flowconfig

@ -8,7 +8,6 @@
[include]
[libs]
flow
[options]
module.name_mapper='^compiler/\(.*\)$' -> '<PROJECT_ROOT>/src/compiler/\1'

10
flow/declarations.js

@ -1,10 +0,0 @@
declare class Vue {
_render: Function;
}
declare interface VNode {
tag: ?string;
text: ?string;
data: ?Object;
children: ?Array<VNode>;
}

2
src/compiler/directives/ref.js

@ -12,6 +12,6 @@ export function ref (el, dir) {
}
// __registerRef__(name, ref, vFor?, remove?)
const code = `__registerRef__("${dir.arg}", n1.child || n1.elm, ${isFor ? 'true' : 'false'}`
addHook(el, 'insert', `${code})`)
addHook(el, 'insert', `${code}), false`)
addHook(el, 'destroy', `${code}, true)`)
}

26
src/core/config.js

@ -1,15 +1,17 @@
/* @flow */
const config: {
preserveWhitespace: boolean,
silent: boolean,
isReservedTag: (x: string) => boolean,
isUnknownElement: (x: string) => boolean,
_assetTypes: Array<string>,
_lifecycleHooks: Array<string>,
_maxUpdateCount: number,
_isServer: boolean
} = {
export type Config = {
preserveWhitespace: boolean,
silent: boolean,
isReservedTag: (x: string) => boolean,
isUnknownElement: (x: string) => boolean,
_assetTypes: Array<string>,
_lifecycleHooks: Array<string>,
_maxUpdateCount: number,
_isServer: boolean
}
const config: Config = {
/**
* Preserve whitespaces between elements.
@ -25,13 +27,13 @@ const config: {
* Check if a tag is reserved so that it cannot be registered as a
* component. This is platform-dependent and may be overwritten.
*/
isReservedTag: () => false,
isReservedTag: _ => false,
/**
* Check if a tag is an unknown element.
* Platform-dependent.
*/
isUnknownElement: () => false,
isUnknownElement: _ => false,
/**
* List of asset types that a component can own.

7
src/core/index.js

@ -1,8 +1,15 @@
import Vue from './instance/index'
import config from './config'
import { initGlobalAPI } from './global-api/index'
initGlobalAPI(Vue)
// defining $isServer flag here because flow cannot handle
// Object.defineProperty getters
Object.defineProperty(Vue.prototype, '$isServer', {
get: () => config._isServer
})
Vue.version = '2.0.0-alpha.0'
export default Vue

38
src/core/instance/events.js

@ -1,7 +1,10 @@
/* @flow */
import type Vue from './index'
import { toArray } from '../util/index'
import { updateListeners } from '../vdom/helpers'
export function initEvents (vm) {
export function initEvents (vm: Vue) {
vm._events = Object.create(null)
// init parent attached events
const listeners = vm.$options._parentListeners
@ -12,21 +15,13 @@ export function initEvents (vm) {
}
}
export function eventsMixin (Vue) {
Vue.prototype.$on = function (event, fn) {
(this._events[event] || (this._events[event] = []))
.push(fn)
export function eventsMixin (Vue: Class<Vue>) {
Vue.prototype.$on = function (event: string, fn: Function): Vue {
(this._events[event] || (this._events[event] = [])).push(fn)
return this
}
/**
* Adds an `event` listener that will be invoked a single
* time then automatically removed.
*
* @param {String} event
* @param {Function} fn
*/
Vue.prototype.$once = function (event, fn) {
Vue.prototype.$once = function (event: string, fn: Function): Vue {
const self = this
function on () {
self.$off(event, on)
@ -37,14 +32,7 @@ export function eventsMixin (Vue) {
return this
}
/**
* Remove the given callback for `event` or all
* registered callbacks.
*
* @param {String} event
* @param {Function} fn
*/
Vue.prototype.$off = function (event, fn) {
Vue.prototype.$off = function (event?: string, fn?: Function): Vue {
// all
if (!arguments.length) {
this._events = Object.create(null)
@ -72,12 +60,7 @@ export function eventsMixin (Vue) {
return this
}
/**
* Trigger an event on self.
*
* @param {String} event
*/
Vue.prototype.$emit = function (event) {
Vue.prototype.$emit = function (event: string): Vue {
let cbs = this._events[event]
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
@ -86,5 +69,6 @@ export function eventsMixin (Vue) {
cbs[i].apply(this, args)
}
}
return this
}
}

98
src/core/instance/index.js

@ -1,3 +1,9 @@
/* @flow */
import type { Config } from '../config'
import type VNode from '../vdom/vnode'
import type Watcher from '../observer/watcher'
import { initProxy } from './proxy'
import { initState, stateMixin } from './state'
import { initRender, renderMixin } from './render'
@ -8,11 +14,99 @@ import { mergeOptions } from '../util/index'
let uid = 0
export default class Vue {
constructor (options) {
// static properties
static cid: number;
static options: Object;
static config: Config;
static util: Object;
// static methods
static set: (obj: Object, key: string, value: any) => void;
static delete: (obj: Object, key: string) => void;
static nextTick: (fn: Function, context?: Object) => void;
static use: (plugin: Function | Object) => void;
static mixin: (mixin: Object) => void;
static extend: (options: Object) => Class<Vue>;
static compile: (template: string) => { render: Function, staticRenderFns: Array<Function> };
// assets
static directive: (id: string, def?: Function | Object) => Function | Object | void;
static component: (id: string, def?: Class<Vue> | Object) => Class<Vue>;
static transition: (id: string, def?: Object) => Object | void;
static filter: (id: string, def?: Function) => Function | void;
// public properties
$el: Element | void;
$data: Object;
$options: Object;
$parent: Vue | void;
$root: Vue;
$children: Array<Vue>;
$refs: { [key: string]: Vue | Element };
$slots: { [key: string]: Array<VNode> };
$isServer: boolean;
// public methods
$mount: (el?: Element | string) => Vue;
$forceUpdate: () => void;
$destroy: () => void;
$watch: (expOrFn: string | Function, cb: Function, options?: Object) => Function;
$on: (event: string, fn: Function) => Vue;
$once: (event: string, fn: Function) => Vue;
$off: (event?: string, fn?: Function) => Vue;
$emit: (event: string, ...args: Array<any>) => Vue;
$nextTick: (fn: Function) => void;
$createElement: (
tag?: string | Vue,
data?: Object,
children?: Array<?VNode> | string,
namespace?: string
) => VNode;
// private properties
_uid: number;
_isVue: true;
_renderProxy: Vue;
_watchers: Array<Watcher>;
_data: Object;
_events: { [key: string]: Array<Function> };
_isMounted: boolean;
_isDestroyed: boolean;
_isBeingDestroyed: boolean;
_vnode: ?VNode;
_staticTrees: ?Array<VNode>;
// private methods
// lifecycle
_mount: () => Vue;
_update: (vnode: VNode) => void;
_updateFromParent: (propsData?: Object, listeners?: Object, parentVnode: VNode, renderChildren: Array<VNode> | () => Array<VNode>) => void;
// rendering
_render: () => VNode;
__h__: (
tag?: string | Vue,
data?: Object,
children?: Array<?VNode> | string,
namespace?: string
) => VNode;
__toString__: (value: any) => string;
__resolveFilter__: (id: string) => Function;
__renderList__: (
val: any,
render: Function
) => ?Array<VNode>;
__registerRef__: (
key: string,
ref: Vue | Element,
vFor: boolean,
isRemoval: boolean
) => void;
constructor (options?: Object) {
this._init(options)
}
_init (options) {
_init (options?: Object) {
// a uid
this._uid = uid++
// a flag to avoid this being observed

29
src/core/instance/lifecycle.js

@ -1,9 +1,13 @@
/* @flow */
import type Vue from './index'
import type VNode from '../vdom/vnode'
import Watcher from '../observer/watcher'
import { warn, validateProp, remove } from '../util/index'
import { observerState } from '../observer/index'
import { updateListeners } from '../vdom/helpers'
export function initLifecycle (vm) {
export function initLifecycle (vm: Vue) {
const options = vm.$options
vm.$parent = options.parent
@ -15,13 +19,13 @@ export function initLifecycle (vm) {
vm.$children = []
vm.$refs = {}
vm._mounted = false
vm._isMounted = false
vm._isDestroyed = false
vm._isBeingDestroyed = false
}
export function lifecycleMixin (Vue) {
Vue.prototype._mount = function () {
export function lifecycleMixin (Vue: Class<Vue>) {
Vue.prototype._mount = function (): Vue {
if (!this.$options.render) {
this.$options.render = () => this.$createElement('div')
if (process.env.NODE_ENV !== 'production') {
@ -43,7 +47,7 @@ export function lifecycleMixin (Vue) {
callHook(this, 'beforeMount')
this._watcher = new Watcher(this, this._render, this._update)
this._update(this._watcher.value)
this._mounted = true
this._isMounted = true
// root instance, call mounted on self
if (this.$root === this) {
callHook(this, 'mounted')
@ -51,8 +55,8 @@ export function lifecycleMixin (Vue) {
return this
}
Vue.prototype._update = function (vnode) {
if (this._mounted) {
Vue.prototype._update = function (vnode: VNode) {
if (this._isMounted) {
callHook(this, 'beforeUpdate')
}
if (!this._vnode) {
@ -68,12 +72,17 @@ export function lifecycleMixin (Vue) {
if (parentNode) {
parentNode.elm = this.$el
}
if (this._mounted) {
if (this._isMounted) {
callHook(this, 'updated')
}
}
Vue.prototype._updateFromParent = function (propsData, listeners, parentVnode, renderChildren) {
Vue.prototype._updateFromParent = function (
propsData?: Object,
listeners?: Object,
parentVnode: VNode,
renderChildren: Array<VNode> | () => Array<VNode>
) {
this.$options._parentVnode = parentVnode
this.$options._renderChildren = renderChildren
// update props
@ -133,7 +142,7 @@ export function lifecycleMixin (Vue) {
}
}
export function callHook (vm, hook) {
export function callHook (vm: Vue, hook: string) {
vm.$emit('pre-hook:' + hook)
const handlers = vm.$options[hook]
if (handlers) {

2
src/core/instance/proxy.js

@ -1,3 +1,5 @@
/* not type checking this file because flow doesn't play well with Proxy */
import { warn, makeMap } from '../util/index'
let hasProxy, proxyHandlers, initProxy

45
src/core/instance/render.js

@ -1,15 +1,18 @@
import config from '../config'
/* @flow */
import type Vue from './index'
import type VNode from '../vdom/vnode'
import createElement from '../vdom/create-element'
import { emptyVNode } from '../vdom/vnode'
import { flatten } from '../vdom/helpers'
import { bind, isArray, isObject, renderString } from 'shared/util'
import { bind, remove, isArray, isObject, renderString } from 'shared/util'
import { resolveAsset, nextTick } from '../util/index'
export const renderState = {
activeInstance: null
}
export function initRender (vm) {
export function initRender (vm: Vue) {
vm._vnode = null
vm._staticTrees = null
vm.$slots = {}
@ -21,19 +24,13 @@ export function initRender (vm) {
}
}
export function renderMixin (Vue) {
export function renderMixin (Vue: Class<Vue>) {
Vue.prototype.$nextTick = function (fn) {
nextTick(fn, this)
}
Object.defineProperty(Vue.prototype, '$isServer', {
get () {
return config._isServer
}
})
Vue.prototype._render = function () {
if (!this._mounted) {
Vue.prototype._render = function (): VNode {
if (!this._isMounted) {
// render static sub-trees for once on initial render
renderStaticTrees(this)
}
@ -67,8 +64,11 @@ export function renderMixin (Vue) {
}
// render v-for
Vue.prototype.__renderList__ = function (val, render) {
let ret, i, l, keys, key
Vue.prototype.__renderList__ = function (
val: any,
render: () => VNode
): ?Array<VNode> {
let ret: ?Array<VNode>, i, l, keys, key
if (isArray(val)) {
ret = new Array(val.length)
for (i = 0, l = val.length; i < l; i++) {
@ -91,9 +91,14 @@ export function renderMixin (Vue) {
}
// register ref
Vue.prototype.__registerRef__ = function (key, ref, vFor, remove) {
Vue.prototype.__registerRef__ = function (
key: string,
ref: Vue | Element,
vFor: boolean,
isRemoval: boolean
) {
const refs = this.$refs
if (remove) {
if (isRemoval) {
if (vFor) {
remove(refs[key], ref)
} else {
@ -113,17 +118,17 @@ export function renderMixin (Vue) {
}
}
function renderStaticTrees (vm) {
function renderStaticTrees (vm: Vue) {
const staticRenderFns = vm.$options.staticRenderFns
if (staticRenderFns) {
vm._staticTrees = new Array(staticRenderFns.length)
const trees = vm._staticTrees = new Array(staticRenderFns.length)
for (let i = 0; i < staticRenderFns.length; i++) {
vm._staticTrees[i] = staticRenderFns[i].call(vm._renderProxy)
trees[i] = staticRenderFns[i].call(vm._renderProxy)
}
}
}
function resolveSlots (vm, renderChildren) {
function resolveSlots (vm: Vue, renderChildren: () => Array<?VNode> | void) {
if (renderChildren) {
const children = flatten(renderChildren())
const slots = {}

6
src/core/instance/state.js

@ -1,3 +1,5 @@
/* Not type checking this file because flow doesn't play well with Object.defineProperty */
import Watcher from '../observer/watcher'
import Dep from '../observer/dep'
import {
@ -155,10 +157,10 @@ export function stateMixin (Vue) {
}
})
Vue.prototype.$watch = function (fn, cb, options) {
Vue.prototype.$watch = function (expOrFn, cb, options) {
options = options || {}
options.user = true
const watcher = new Watcher(this, fn, cb, options)
const watcher = new Watcher(this, expOrFn, cb, options)
if (options.immediate) {
cb.call(this, watcher.value)
}

2
src/core/vdom/create-component.js

@ -62,7 +62,7 @@ export function createComponent (Ctor, data, parent, children, context) {
// return a placeholder vnode
const name = Ctor.options.name ? ('-' + Ctor.options.name) : ''
const vnode = VNode(
const vnode = new VNode(
`vue-component-${Ctor.cid}${name}`, data,
undefined, undefined, undefined, undefined, context
)

4
src/core/vdom/create-element.js

@ -15,7 +15,7 @@ export default function createElement (tag, data, children, namespace) {
if (typeof tag === 'string') {
let Ctor
if (config.isReservedTag(tag)) {
return VNode(
return new VNode(
tag, data, flatten(children),
undefined, undefined, namespace, context
)
@ -31,7 +31,7 @@ export default function createElement (tag, data, children, namespace) {
)
}
}
return VNode(
return new VNode(
tag, data, flatten(children && children()),
undefined, undefined, namespace, context
)

6
src/core/vdom/helpers.js

@ -1,11 +1,11 @@
import { isArray, isPrimitive } from '../util/index'
import VNode from './vnode'
const whitespace = VNode(undefined, undefined, undefined, ' ')
const whitespace = new VNode(undefined, undefined, undefined, ' ')
export function flatten (children) {
if (typeof children === 'string') {
return [VNode(undefined, undefined, undefined, children)]
return [new VNode(undefined, undefined, undefined, children)]
}
if (isArray(children)) {
const res = []
@ -20,7 +20,7 @@ export function flatten (children) {
res.push(whitespace)
} else {
// convert primitive to vnode
res.push(VNode(undefined, undefined, undefined, c))
res.push(new VNode(undefined, undefined, undefined, c))
}
} else if (c) {
res.push(c)

4
src/core/vdom/patch.js

@ -6,7 +6,7 @@
import VNode from './vnode'
import { isPrimitive, renderString, warn } from '../util/index'
const emptyNode = VNode('', {}, [])
const emptyNode = new VNode('', {}, [])
const hooks = ['create', 'update', 'remove', 'destroy']
function isUndef (s) {
@ -45,7 +45,7 @@ export function createPatchFunction (backend) {
}
function emptyNodeAt (elm) {
return VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)
return new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)
}
function createRmCb (childElm, listeners) {

33
src/core/vdom/vnode.js

@ -1,14 +1,25 @@
export default function VNode (tag, data, children, text, elm, ns, context) {
return {
tag,
data,
children,
text,
elm,
ns,
context,
key: data && data.key
import type Vue from 'core/instance/index'
export default class VNode {
tag: string | void;
data: Object | void;
children: Array<VNode> | void;
text: string | void;
elm: Element | void;
ns: string | void;
context: Vue | void;
key: string | number | void;
constructor (tag, data, children, text, elm, ns, context) {
this.tag = tag
this.data = data
this.children = children
this.text = text
this.elm = elm
this.ns = ns
this.context = context
this.key = data && data.key
}
}
export const emptyVNode = VNode(undefined, undefined, undefined, '')
export const emptyVNode = new VNode(undefined, undefined, undefined, '')

2
src/platforms/web/runtime/modules/transition.js

@ -42,7 +42,7 @@ export function enter (vnode) {
if (!data) {
return
}
if (!vnode.context.$root._mounted && !data.appear) {
if (!vnode.context.$root._isMounted && !data.appear) {
return
}

3
src/server/create-renderer.js

@ -1,10 +1,11 @@
/* @flow */
import type Vue from 'core/instance/index'
import RenderStream from './render-stream'
import { createRenderFunction } from './render'
import { warn } from 'core/util/debug'
export const MAX_STACK_DEPTH = 10
export const MAX_STACK_DEPTH = 1000
export function createRenderer ({
modules = [],

2
src/server/render.js

@ -1,5 +1,7 @@
/* @flow */
import type Vue from 'core/instance/index'
import type VNode from 'core/vdom/vnode'
import { createComponentInstanceForVnode } from 'core/vdom/create-component'
export function createRenderFunction (

Loading…
Cancel
Save