想要一天彻底搞懂 Vue 2 的原理,确实是一项挑战,但并非不可能。下面是一个学习计划,以及补充Vue2原理的重要性和实际价值的说明。
初始化流程
-
初始化Vue的指令
a. 对vue实例的options属性进行合并
-
初始化mixin
a. 对vue实例的options属性进行合并
-
初始化插件
a. 执行插件定义的install 方法
我们先来看Vue是怎么渲染在页面中的,html结构如下
const vm = new MiniVue({
el: '#app',
data: {
newAge: 20,
age: 18,
name: '小马',
obj: {
a: {
msg: 'abc'
}
},
select: ['v1', 2, 3, 4],
pick: '',
checkedNames: [],
address: ['中国', '天津', '南开'],
html: '<span style="color:red">这是一段v-html</span>',
show: 'a',
newAddress: ['银河', '太阳', '地球'],
if: true
},
// 五个生命周期函数
init() {
console.log('init')
},
created() {
console.log('created')
},
beforeCompile() {
console.log('beforeCompile')
},
compiled() {
console.log('compiled')
},
destroyed() {
console.log('destroyed')
},
directives: {
'my-directive': objd
},
methods: {
increase() {
this.age++
},
reset() {
this.address = ['中国', '天津', '南开']
},
sayHi() {
console.log('父组件有一个自己的sayHi方法')
},
sayTest(msg) {
console.log('hi, ' + msg)
}
},
computed: {
comTest() {
return this.age + ' ' + this.name
}
},
filters: {
capitalize(value) {
if (!value) {
return ''
}
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
},
components: {
'my-component': obj
},
mixin: {
methods: {
newMixin() {
console.log('newMixin')
}
}
},
computed: {
comTest() {
return this.age + ' ' + this.name
}
}
})
看下 MiniVue构造函数的定义,这里MiniVue就可以理解为Vue,我们对模型进行了简化。
function MiniVue(options) {
debugger
this._init(options)
}
看看__init看了啥
_init(options) {
this.$el = null
this.$parent = options.parent
// MiniVue实例
this._isMiniVue = true
// 根组件
this.$root = this.$parent? this.$parent.$root : this
// 存放子组件
this.$children = []
// 存放观察者实例
this._watchers = []
// 存放事件
this._events = {}
// 存放指令
this._directives = []
// 父级上下文对象
this._context = options._context || this.$parent
if (this.$parent) {
this.$parent.$children.push(this)
}
// 合并参数
// 在这里将用到的components继承Vue实例
options = this.$options = mergeOptions(this.constructor.options, options, this)
this._callHook('init')
this._initMixins()
this._initComponents()
this._initProps()
this._initMethods()
this._initData()
this._initWatch()
this._initComputed()
this._initEvents()
this._callHook('created')
if (options.el) {
this._compile()
}
},
初始化mixin
// 局部mixin
_initMixins() {
let options = this.$options
if (options.mixin) {
this.$options = mergeOptions(options, options.mixin)
}
},
初始化components
// 局部componet
_initComponents() {
const components = this.$options.components
const keys = Object.keys(components)
keys.forEach(key => {
components[key] = MiniVue.component(key, components[key], true)
})
},
看props处理
export function getBindAttr(node, name) {
let val = getAttr(node, ':' + name)
if (val === null) {
val = getAttr(node, 'v-bind:' + name)
}
return val
}
if ((value = getBindAttr(el, name)) !== null) {
// 动态绑定
// 如果是:xxxx 则给动态标记
prop.dynamic = true
prop.raw = prop.parentPath = value
} else if ((value = getAttr(el, name)) !== null) {
// 静态绑定
prop.raw = value
}
会把prop转成一个对象,如下图:
然后把这个对象push到props中