实例化 Vue
<div id="app">原来的dom {{message}}</div>
// 非单文件组件
new Vue({
el:"#app",
data:{
msg:"hello world!"
},
// 不存在 template 时,vue会对原来的dom进行编译,
// 存在 template 时,template 编译完成会替换原来的dom
template:`
<h1>模板里的dom {{message}}</h1>
`
});
// 单文件组件
new Vue({
render:h=>h(App);
}).$mount("#app");
Vue 构造函数
import { initMixin } from "./init";
import { stateMinxin } from "./state";
import { renderMixin } from "./render";
import { eventsMixin } from "./events";
import { lifecycleMixin } from "./lifecycle"
function Vue(options) {
// 不使用 new 操作符调用 Vue 时的警告
this._init(options);
}
initMixin(Vue); // * 向 Vue 的原型上挂载 _init 方法,进行初始化
stateMinxin(Vue); // 向 Vue 的原型上挂载 $set、$watch、$delete 实例方法
eventsMixin(Vue); // 向 Vue 原型上挂载 $on、$emit、$off、$once 方法
lifecycleMixin(Vue); // 挂载与生命周期相关的方法,$forceUpdate 和 $destroy
renderMixin(Vue); // 目前只了解到,向 Vue 原型上挂载$nextTick
export default Vue;
Vue.js通过调用 initMixin 方法将 _init 挂载到Vue 构造函数的原型上,然后调用this._init(options)来执行生命周期的初始化流程,_init 的挂载和内部实现如下:
export function initMixin(Vue) {
Vue.prototype._init = function (options) {
// 操作 options
initLifecycle(vm); // 向实例中挂载属性
initEvents(vm);
initRender(vm);
callHook(vm, 'beforeCreate'); // 从Vue实例的配置项中获取并触发用户设置的生命周期钩子
initInjections(vm) // 在data、props前初始化inject
initState(vm) // 初始化状态props、methods、data、computed、watch
initProvide(vm) // 在data、props后初始化provide
callHook(vm, 'created')
// 如果用户在实例化Vue.js时传递了el选项,则自动开启模板编译阶段与挂载阶段
// 如果没有传递el选项,则不进入下一个生命周期流程,用户需要执行vm.$mount方法,手动开启模板编译阶段与挂载阶段
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
}
initLifecycle 函数
向 vue 实例中挂载属性。该函数接收 vue 实例作为参数。只需要向 vue 实例设置属性就可以挂载到 vue 实例上,包括以 美元符号 开头提供给用户使用的属性($$ref、$parent),以 _ 开头提供给内部使用的属性(_data、_watcher)。
initEvents 函数
初始化的事件,指的是父组件在模板中使用 v-on 监听子组件内触发的事件。在模板编译阶段,被编译的标签为组件标签时,会实例化子组件,同时将标签上注册的事件解析成 object 并通过参数传递给子组件。下面要讲的 props 状态也是如此。
initState 函数
- 初始化状态,当在创建 vue 实例时,只要向其中配置了哪些状态会在 initState 函数中进行初始化,没有配置就不需要初始化。
- 初始化的顺序也是精心设计的,先初始化props ,后初始化data ,这样就可以在data中使用props 中 的数据了。在watch 中既可以观察props ,也可以观察data。
规格化 props
props 的注意点:
// 如果在父组件的模板中使用这样的语法:
<child user-name="berwin" user-age="18" user-gender="男"></child>
// 错误写法
props:['user-name','user-age','user-gender']
// Vue 内部使调用 camelize 函数将 props 名称驼峰化,即可以将 a-b 这样的名称转换成aB 。
// 正确写法
props:['userName','userAge','userGender']
当 props 通过数组指定需要哪些属性。但在 Vue 内部,数组格式的 props 将被规格化成对象格式。
// 规格化前
// props:['userName','userAge','userGender']
// 部分源码
if (Array.isArray(props)) {
i = props.length
while (i--) {
val = props[i]
if (typeof val === 'string') {
name = camelize(val)
res[name] = { type: null }
}
}
options.props = res;
// 规格化后
props:{
userName:{ type : null },
userAge:{ type : null },
userGender:{ type : null }
}
初始化 Methods
初始化 Methods 需要,循环选项中的 methods 对象,依次对每一个属性进行检验,然后挂载到 vue实例上。 检验条件有三个(不满足其中一个控制台就会警告):
1、同时有key和value;
2、不与 props 中的属性重名;
3、不以 $ 和 _ 开头。
挂载:
vm[key] = methods[key] == null ? noop : bind(methods[key], vm)
未完待续 . . .