[TOC]
******
## 6 [\core\instance\] 實例核心目錄
### 6-1 目錄層次
~~~
\core\instance\
index.js ;核心實例接口
lifecycle.js ;核心生命周期接口
proxy.js ;核心代理接口
state.js ;核心狀態接口
events.js ;核心事件接口
render.js ;核心渲染接口
~~~

### 6-2 (index.js) 核心實例接口
>[info] import
~~~
;(導入)代理,狀態,渲染,事件,生命周期,基礎工具
import { initProxy } from './proxy'
import { initState, stateMixin } from './state'
import { initRender, renderMixin } from './render'
import { initEvents, eventsMixin } from './events'
import { initLifecycle, lifecycleMixin, callHook } from './lifecycle'
import { nextTick, mergeOptions } from '../util/index'
~~~
>[info] module
~~~
;全局uid
let uid = 0
;Vue._init()初始化接口
Vue.prototype._init = function (options) {
// a uid
this._uid = uid++
// a flag to avoid this being observed
this._isVue = true
// merge options
this.$options = mergeOptions(
this.constructor.options,
options || {},
this
)
;初始化代理
if (process.env.NODE_ENV !== 'production') {
initProxy(this)
} else {
this._renderProxy = this
}
;初始化生命周期,事件
initLifecycle(this)
initEvents(this)
;回調init鉤子
callHook(this, 'init')
;初始化Vue內部狀態
initState(this)
;回調created鉤子
callHook(this, 'created')
;初始化渲染
initRender(this)
}
;Vue.$nextTick()接口
Vue.prototype.$nextTick = function (fn) {
nextTick(fn, this)
}
;安裝其他核心實例接口
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
~~~
>[info] export
~~~
(導出)Vue實例化接口
export default function Vue (options) {
this._init(options)
}
~~~

### 6-3 (lifecycle.js) 核心生命周期接口
>[info] import
~~~
;(導入)監視器接口,基礎攻擊,依賴接口,虛擬機DOM接口
import Watcher from '../observer/watcher'
import { warn, validateProp, remove } from '../util/index'
import { observerState } from '../observer/index'
import { updateListeners } from '../vdom/helpers'
~~~
>[info] module
~~~
;生命周期(lifecycle)初始化接口
export function initLifecycle (vm) {
;初始化參數$options
const options = vm.$options
;父節點與根節點
vm.$parent = options.parent
vm.$root = vm.$parent ? vm.$parent.$root : vm
if (vm.$parent) {
vm.$parent.$children.push(vm)
}
;孩子節點,索引對象
vm.$children = []
vm.$refs = {}
;狀態初始化
vm._isDestroyed = false
vm._isBeingDestroyed = false
}
;生命周期安裝接口
export function lifecycleMixin (Vue) {
;1 Vue._mount() VM掛載dom節點接口
Vue.prototype._mount = function () {
;檢查渲染函數
if (!this.$options.render) {
this.$options.render = () => this.$createElement('div')
if (process.env.NODE_ENV !== 'production') {
if (this.$options.template) {
warn(
'You are using the runtime-only build of Vue where the template ' +
'option is not available. Either pre-compile the templates into ' +
'render functions, or use the compiler-included build.',
this
)
} else {
warn(
'Failed to mount component: template or render function not defined.',
this
)
}
}
}
;渲染靜態樹
const staticRenderFns = this.$options.staticRenderFns
if (staticRenderFns) {
this._staticTrees = new Array(staticRenderFns.length)
for (let i = 0; i < staticRenderFns.length; i++) {
this._staticTrees[i] = staticRenderFns[i].call(this._renderProxy)
}
}
;this._watcher,this._update(),this._mounted狀態修改
this._watcher = new Watcher(this, this._render, this._update)
this._update(this._watcher.value)
this._mounted = true
;ready鉤子回調處理
if (this.$root === this) {
callHook(this, 'ready')
}
return this
}
; 2 Vue._update() 刷新節點接口
Vue.prototype._update = function (vnode) {
;檢查掛載狀態,調用節點刷新前beforeUpdate鉤子
if (this._mounted) {
callHook(this, 'beforeUpdate')
}
;父節點
const parentNode = this.$options._parentVnode
vnode.parent = parentNode
;調用this.__patch__生成虛擬節點this._vnode
if (!this._vnode) {
this.$el = this.__patch__(this.$el, vnode)
} else {
this.$el = this.__patch__(this._vnode, vnode)
}
this._vnode = vnode
;掛載到父級節點上
if (parentNode) {
parentNode.elm = this.$el
}
;調用更新完后updated鉤子
if (this._mounted) {
callHook(this, 'updated')
}
}
; 3 Vue._updateFromParent() 從父節點刷新接口
Vue.prototype._updateFromParent = function (propsData, listeners, parentVnode, renderChildren) {
this.$options._parentVnode = parentVnode
this.$options._renderChildren = renderChildren
if (propsData && this.$options.props) {
observerState.shouldConvert = false
const propKeys = this.$options.propKeys
for (let i = 0; i < propKeys.length; i++) {
const key = propKeys[i]
this[key] = validateProp(this, key, propsData)
}
observerState.shouldConvert = true
}
if (listeners) {
const oldListeners = this.$options._parentListeners
this.$options._parentListeners = listeners
updateListeners(listeners, oldListeners || {}, (event, handler) => {
this.$on(event, handler)
})
}
}
; 4 Vue.$forceUpdate() 強制刷新接口
Vue.prototype.$forceUpdate = function () {
this._watcher.update()
}
; 5 Vue.$destroy() 強制銷毀接口
Vue.prototype.$destroy = function () {
if (this._isDestroyed) {
return
}
callHook(this, 'beforeDestroy')
this._isBeingDestroyed = true
const parent = this.$parent
if (parent && !parent._isBeingDestroyed) {
remove(parent.$children, this)
}
if (this._ref) {
this._context.$refs[this._ref] = undefined
}
let i = this._watchers.length
while (i--) {
this._watchers[i].teardown()
}
if (this._data.__ob__) {
this._data.__ob__.removeVm(this)
}
this._isDestroyed = true
callHook(this, 'destroyed')
this.$off()
}
}
~~~
>[info] export
~~~
;(導出)生命周期初始化接口
export function initLifecycle (vm){}
;(導出)生命周期安裝接口
export function lifecycleMixin (Vue) {}
;(導出)鉤子回調接口
export function callHook (vm, hook) {}
~~~

### 6-4 (proxy.js) 核心代理接口
>[info] import
~~~
;基礎工具
import { warn, makeMap } from '../util/index'
~~~
>[info] module
~~~
;聲明三個變量
let hasProxy, proxyHandlers, initProxy
;實現三個功能函數
if (process.env.NODE_ENV !== 'production') {
const allowedGlobals = makeMap(
'Infinity,undefined,NaN,isFinite,isNaN,' +
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl'
)
;判斷平臺是否支持Proxy功能
hasProxy =
typeof Proxy !== 'undefined' &&
Proxy.toString().match(/native code/)
;注冊Proxy的處理函數
proxyHandlers = {
has (target, key) {
const has = key in target
const isAllowedGlobal = allowedGlobals(key)
if (!has && !isAllowedGlobal) {
warn(
`Trying to access non-existent property "${key}" while rendering.`,
target
)
}
return !isAllowedGlobal
}
}
;初始化代理initProxy() 注冊vm._renderProxy屬性
initProxy = function initProxy (vm) {
if (hasProxy) {
vm._renderProxy = new Proxy(vm, proxyHandlers)
} else {
vm._renderProxy = vm
}
}
}
~~~
>[info] export
~~~
;(導出)initProxy()作為注冊 vm._renderProxy屬性接口
export { initProxy }
~~~

### 6-5 (state.js) 核心狀態接口
>[info] import
~~~
;(導入)Watcher,Dep,observer,util等接口
import Watcher from '../observer/watcher'
import Dep from '../observer/dep'
import {
observe,
defineReactive,
observerState,
proxy,
unproxy
} from '../observer/index'
import {
warn,
hasOwn,
isArray,
isPlainObject,
bind,
validateProp
} from '../util/index'
~~~
>[info] module
~~~
;Vm內部狀態初始化接口
;包括Props,Data,Computed,Methods,Watch等屬性的初始化
export function initState (vm) {
vm._watchers = []
initProps(vm)
initData(vm)
initComputed(vm)
initMethods(vm)
initWatch(vm)
}
;(1) Props屬性初始化
function initProps (vm) {
;獲取初始化props參數
const props = vm.$options.props
const propsData = vm.$options.propsData
;檢查是否存在props,然后進行初始化
if (props) {
;獲取props的keys,
const keys = vm.$options.propKeys = Object.keys(props)
;判斷當前vm是否是根節點,標記其狀態
const isRoot = !vm.$parent
observerState.shouldConvert = isRoot
;注冊propsData到props中
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
defineReactive(vm, key, validateProp(vm, key, propsData))
}
;根節點狀態標記
observerState.shouldConvert = true
}
}
;(2) Data屬性初始化
function initData (vm) {
;獲取初始化data參數
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? data()
: data || {}
;參數有效性檢查
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object.',
vm
)
}
;獲取Data的keys
const keys = Object.keys(data)
let i = keys.length
;注冊keys鍵到vm
while (i--) {
proxy(vm, keys[i])
}
;進行數據監視
observe(data, vm)
}
;空函數聲明
function noop () {}
;(3) Computed屬性初始化
function initComputed (vm) {
;獲取初始化computed參數
const computed = vm.$options.computed
;檢查初始化參數并進行處理
if (computed) {
;computed屬性信息合成
for (const key in computed) {
const userDef = computed[key]
const def = {
enumerable: true,
configurable: true
}
if (typeof userDef === 'function') {
def.get = makeComputedGetter(userDef, vm)
def.set = noop
} else {
def.get = userDef.get
? userDef.cache !== false
? makeComputedGetter(userDef.get, vm)
: bind(userDef.get, vm)
: noop
def.set = userDef.set
? bind(userDef.set, vm)
: noop
}
;注冊computed屬性到vm
Object.defineProperty(vm, key, def)
}
}
}
;生成computed的get函數
function makeComputedGetter (getter, owner) {
;生成watcher
const watcher = new Watcher(owner, getter, null, {
lazy: true
})
return function computedGetter () {
if (watcher.dirty) {
watcher.evaluate()
}
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
;(4) Method屬性初始化
function initMethods (vm) {
;獲取初始化methods參數
const methods = vm.$options.methods
;綁定method到vm
if (methods) {
for (const key in methods) {
vm[key] = bind(methods[key], vm)
}
}
}
;(5) Watch屬性初始化
function initWatch (vm) {
;獲取初始化watch參數
const watch = vm.$options.watch
;檢查watch參數,創建watch注冊到vm
if (watch) {
for (const key in watch) {
const handler = watch[key]
if (isArray(handler)) {
for (let i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i])
}
} else {
createWatcher(vm, key, handler)
}function createWatcher (vm, key, handler) {
let options
if (isPlainObject(handler)) {
options = handler
handler = handler.handler
}
if (typeof handler === 'string') {
handler = vm[handler]
}
vm.$watch(key, handler, options)
}
}
}
}
;創建watch注冊到vm
function createWatcher (vm, key, handler) {
let options
if (isPlainObject(handler)) {
options = handler
handler = handler.handler
}
if (typeof handler === 'string') {
handler = vm[handler]
}
vm.$watch(key, handler, options)
}
;狀態操作安裝接口
export function stateMixin (Vue) {
;$vm.data注冊
Object.defineProperty(Vue.prototype, '$data', {
get () {
return this._data
},
set (newData) {
if (newData !== this._data) {
setData(this, newData)
}
}
})
;Vue.$watch注冊
Vue.prototype.$watch = function (fn, cb, options) {
options = options || {}
options.user = true
const watcher = new Watcher(this, fn, cb, options)
if (options.immediate) {
cb.call(this, watcher.value)
}
return function unwatchFn () {
watcher.teardown()
}
}
}
;_data屬性的修改函數
function setData (vm, newData) {
;獲取data比較參數
newData = newData || {}
const oldData = vm._data
vm._data = newData
;遍歷刪除不存在的key
let keys, key, i
keys = Object.keys(oldData)
i = keys.length
while (i--) {
key = keys[i]
if (!(key in newData)) {
unproxy(vm, key)
}
}
;注冊添加的key
keys = Object.keys(newData)
i = keys.length
while (i--) {
key = keys[i]
if (!hasOwn(vm, key)) {
proxy(vm, key)
}
}
;強制刷新處理
oldData.__ob__.removeVm(vm)
observe(newData, vm)
vm.$forceUpdate()
}
~~~
>[info] export
~~~
;(導出)狀態初始化接口
export function initState (vm){}
;(導出)狀態操作安裝接口
export function stateMixin (Vue){}
~~~

### 6-6 (events.js) 核心事件接口
>[info] import
~~~
;(導入)數組轉換,vdom的事件接口
import { toArray } from '../util/index'
import { updateListeners } from '../vdom/helpers'
~~~
>[info] module
~~~
;事件初始化接口
export function initEvents (vm) {
;創建vm._events
vm._events = Object.create(null)
;獲取初始化_parentListeners參數
const listeners = vm.$options._parentListeners
;檢查參數是否存在并安裝事件監聽接口
if (listeners) {
updateListeners(listeners, {}, (event, handler) => {
vm.$on(event, handler)
})
}
}
~~~
~~~
;事件操作安裝接口
export function eventsMixin (Vue) {
;Vue.$on()事件安裝接口
Vue.prototype.$on = function (event, fn) {
(this._events[event] || (this._events[event] = []))
.push(fn)
return this
}
;Vue.$once()事件安裝接口
Vue.prototype.$once = function (event, fn) {
const self = this
function on () {
self.$off(event, on)
fn.apply(this, arguments)
}
on.fn = fn
this.$on(event, on)
return this
}
;Vue.$off()事件注銷接口
Vue.prototype.$off = function (event, fn) {
;獲取參數
if (!arguments.length) {
this._events = Object.create(null)
return this
}
;注冊
const cbs = this._events[event]
if (!cbs) {
return this
}
;注銷所有事件回調
if (arguments.length === 1) {
this._events[event] = null
return this
}
;特殊事件注銷
let cb
let i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
}
}
return this
}
;Vue.$emit()事件觸發接口
Vue.prototype.$emit = function (event) {
;獲取事件回調接口
let cbs = this._events[event]
;調用事件對應回調
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)
for (let i = 0, l = cbs.length; i < l; i++) {
cbs[i].apply(this, args)
}
}
}
}
~~~
>[info] export
~~~
;(導出)事件初始化接口
export function initEvents (vm) {}
;(導出)事件操作安裝接口
export function eventsMixin (Vue) {}
~~~
### 6-7 (render.js) 核心渲染接口
>[info] import
~~~
(導入)vdom操作接口與基礎攻擊
import createElement from '../vdom/create-element'
import { flatten } from '../vdom/helpers'
import { bind, isArray, isObject, renderString } from 'shared/util'
import { resolveAsset } from '../util/options'
~~~
>[info] module
~~~
;渲染實例
export const renderState = {
activeInstance: null
}
;渲染初始化接口
export function initRender (vm) {
;創建vm_vnode,vm_mounted,vm._staticTress,
vm._vnode = null
vm._mounted = false
vm._staticTrees = null
;創建vm.$slots,vm.$createElement
vm.$slots = {}
vm.$createElement = bind(createElement, vm)
;檢查初始化el參數,并調用vm.$mount實現掛載
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
;渲染操作安裝接口
export function renderMixin (Vue) {
;Vue._render()接口
Vue.prototype._render = function () {
;保存上個渲染實例,設置當前渲染實例
const prev = renderState.activeInstance
renderState.activeInstance = this
;獲取render,_renderChildren渲染參數
const { render, _renderChildren } = this.$options
;檢查_renderChildren渲染參數,調用resolveSlots()
if (_renderChildren) {
resolveSlots(this, _renderChildren)
}
;虛擬vnode
const vnode = render.call(this._renderProxy)
;恢復上個渲染實例
renderState.activeInstance = prev
;返回虛擬vnode
return vnode
}
;Vue.__h__()渲染接口
Vue.prototype.__h__ = createElement
;Vue.__toString__()渲染接口
Vue.prototype.__toString__ = renderString
const identity = _ => _
;Vue.__renderFilter__()渲染接口
Vue.prototype.__resolveFilter__ = function (id) {
return resolveAsset(this.$options, 'filters', id, true) || identity
}
;Vue.__renderList__()渲染接口
Vue.prototype.__renderList__ = function (val, render) {
let ret, i, l, keys, key
if (isArray(val)) {
ret = new Array(val.length)
for (i = 0, l = val.length; i < l; i++) {
ret[i] = render(val[i], i, i)
}
} else if (typeof val === 'number') {
ret = new Array(val)
for (i = 0; i < val; i++) {
ret[i] = render(i + 1, i, i)
}
} else if (isObject(val)) {
keys = Object.keys(val)
ret = new Array(keys.length)
for (i = 0, l = keys.length; i < l; i++) {
key = keys[i]
ret[i] = render(val[key], i, key)
}
}
return ret
}
;Vue.__registerRef__()渲染接口
Vue.prototype.__registerRef__ = function (key, ref, vFor, remove) {
const refs = this.$refs
if (remove) {
if (vFor) {
remove(refs[key], ref)
} else {
refs[key] = undefined
}
} else {
if (vFor) {
if (refs[key]) {
refs[key].push(ref)
} else {
refs[key] = [ref]
}
} else {
refs[key] = ref
}
}
}
}
function resolveSlots (vm, renderChildren) {
if (renderChildren) {
const children = flatten(renderChildren())
const slots = { default: children }
let i = children.length
let name, child
while (i--) {
child = children[i]
if ((name = child.data && child.data.slot)) {
const 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
}
}
~~~
>[info] export
~~~
;(導出)渲染實例
export const renderState={}
;(導出)渲染初始化接口
export function initRender (vm) {}
;(導出)渲染安裝接口
export function renderMixin (Vue) {}
~~~

- 概述
- 框架結構
- 編譯入口(\entries)
- web-compiler.js(web編譯)
- web-runtime.js(web運行時)
- web-runtime-wih-compiler.js(web編譯運行)
- web-server-renderer.js(web服務器渲染)
- 核心實現 (\core)
- index.js(核心入口)
- config.js(核心配置)
- core\util(核心工具)
- core\observer(雙向綁定)
- core\vdom(虛擬DOM)
- core\global-api(核心api)
- core\instance(核心實例)
- 模板編譯(\compiler)
- compiler\parser(模板解析)
- events.js(事件解析)
- helper.js(解析助手)
- directives\ref.js(ref指令)
- optimizer.js(解析優化)
- codegen.js(渲染生成)
- index.js(模板編譯入口)
- web渲染(\platforms\web)
- compiler(web編譯目錄)
- runtime(web運行時目錄)
- server(web服務器目錄)
- util(web工具目錄)
- 服務器渲染(\server)
- render-stream.js(流式渲染)
- render.js(服務器渲染函數)
- create-renderer.js(創建渲染接口)
- 框架流程
- Vue初始化
- Vue視圖數據綁定
- Vue數據變化刷新
- Vue視圖操作刷新
- 框架工具
- 基礎工具(\shared)
- 模板編譯助手
- 核心實例工具
- Web渲染工具
- 基礎原理
- dom
- string
- array
- function
- object
- es6
- 模塊(Module)
- 類(Class)
- 函數(箭頭)
- 字符串(擴展)
- 代理接口(Proxy)
- 數據綁定基礎
- 數據綁定實現
- mvvm簡單實現
- mvvm簡單使用
- vdom算法
- vdom實現
- vue源碼分析資料