new Vue
发生了什么
1. mergeOptions
合并options
2. initLifecycle(vm)
初始化生命周期
3. initEvents(vm)
初始化事件
4. initRender(vm)
:初始化render
初始化渲染
5. callHook(vm, 'beforeCreate')
:触发 beforeCreate
钩子
触发 beforeCreate
钩子
6. initInjections(vm) // resolve injections before data/props
7. initState(vm)
:初始化 props、data、computed、methods
和watch
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
9. initProvide(vm) // resolve provide after data/props
10. callHook(vm, 'created')
:触发 created
钩子
触发 created
钩子
init
function Vue(options) {
this._init(options)
}
initMixin(Vue)
function initMixin(Vue) {
Vue.prototype._init = function(options) {
const vm = this
// 一个防止观察自身的标志
vm._isVue = true
vm.$options = options
}
initState(vm)
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
const inBrowser = typeof window !== 'undefined'
Vue.prototype.$mount = function (el, hydrating) {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
function mountComponent(vm, el, hydrating) {
vm.$el = el
let updateComponent = () => {
vm._update(vm._render(), hydrating)
}
}
// 缓存之前的$mount
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function(el, hydrating) {
el = el && query(el)
const options = this.$options
if (!options.render) {
let template = options.template
if (template) {
// .
} else {
template = getOuterHTML(el)
}
}
return mount.call(this, el, hydrating)
}
function query (el) {
if (typeof el === 'string') {
const selected = document.querySelector(el)
if (!selected) {
// process.env.NODE_ENV !== 'production' && warn(
// 'Cannot find element: ' + el
// )
return document.createElement('div')
}
return selected
} else {
return el
}
}
function getOuterHTML (el) {
if (el.outerHTML) {
return el.outerHTML
} else {
const container = document.createElement('div')
container.appendChild(el.cloneNode(true))
return container.innerHTML
}
}
function initState(vm) {
const opts = vm.$options
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true)
}
}
function initData(vm) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
const keys = Object.keys(data)
let i = keys.length
while (i--) {
proxy(vm, `_data`, key)
}
observe(data, true /* asRootData */)
}
function getData(data, vm) {
return data.call(vm, vm)
}
const sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
}
// 等待,无操作
function noop() {}
function proxy(target, sourceKey, key) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
}
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val
}
Object.defineProperty(target, key, sharedPropertyDefinition)
}
function observe(value, asRootData) {
}
vdom
用js
对象描述真实dom
为什么使用vdom
手动操作dom
比较麻烦,还要考虑兼容性问题,虽然有jquery
等库简化操作,但随着项目增大,复杂度不断提升
为了简化操作dom
,可以使用模板引擎,但是模板引擎没有解决跟踪状态变化的问题,于是vdom
出现了
- 开销更小
- 可以合并更改
- 可以跟踪上一次的状态,并且用作
diff
技巧
将事件的创建和销毁写在一起
在 Vue
中,可以用$on
和$once
去监听所有的生命周期钩子函数,如监听组件的updated
钩子函数可以写成this.$on('hook:updated', () => {})
mounted(){
window.addEventListener('resize', xxx)
// 通过hook监听组件销毁钩子函数,并取消监听事件
this.$once('hook:beforeDestroy', () => {
window.removeEventListener('resize', xxx)
})
}
监听子组件的生命周期
需要监听第三方组件数据的变化,但是组件又没有提供change
事件
<child @hook:updated="childUpdated" />