new Vue(Vue 初始化)

一个vue实例化到底经历了什么?已下是博主自己的总结,不正确的地方请指出,谢谢~

一、简述

从使用角度来看,挂载的顺序如下

1. $slots
2. $scopedSlots
3. beforeCreate
4. inject
5. props
6. methods
7. data
8. computed
9. watch
10. provide
11. created
12. beforeMount
13. mounted

从源码角度来看,运行的顺序如下

Vue实例创建的时候,主要运行了_init函数,他将会调用一系列init函数,以及生命周期函数
1. initEvents(vm)
初始化事件, 将_events(清空), _hasHookEvent(false)挂载到vm实例上, 初始化 listeners
2. initRender(vm)
挂载_vnode, _staticTrees, $slots, $scopedSlots
挂载_c(用于定义虚拟节点), $createElement(用于定义虚拟节点)
使用defineReactive定义 vm 响应式的 $attrs, $listeners
3. callHook(vm, 'beforeCreate')
调用beforeCreate钩子函数
4. initInjections(vm)
读取上一级inject(注入)的变量
用法: inject: ['reload']
5. initState(vm)
依次挂载props, methods, data, computed, watch(都使用了proxy 代理到了vm实例上,所以可以this.的方式去访问)
6. initProvide(vm)
输出本组件的数据,传给需要的子组件
用法: provide () {
return {
reload: this.reload,
xxx: this.ooo,
}
}
7. callHook(vm, 'created')
调用created钩子函数
8. vm.$mount(vm.$options.el) => mountComponent(this, el, hydrating)
(1) callHook(vm, 'beforeMount')
调用beforeMount钩子函数
(2) 添加updateComponent的观察者
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate') // 调用beforeUpdate钩子函数
}
}
}, true ) (3) callHook(vm, 'mounted')
调用mounted钩子函数

使用new Vue

使用 vue-cli创建(vue create 项目名称)项目,找到main.js文件

...
new Vue({
el: '#app',
router,
components: { App },
template: '<App />'
})
...

二、源码层面理解(vue源码)

1. 源码下载

前往git下载 [https://github.com/vuejs](vue-dev源码)

2. Vue 构造函数

文件位置:vue-dev/src/core/index.js

...
function Vue (options) {
...
this._init(options)
} // 为Vue原型(Vue.prototype.)添加各种函数
initMixin(Vue) // 添加 _init 函数
stateMixin(Vue) // 添加 $data, $props, $set, $delete, $watch(expOrFn, cb, options)
eventsMixin(Vue) // 添加 $on, $once, $off, $emit 事件
lifecycleMixin(Vue) // 添加 _update, $forceUpdate, $destroy 函数
renderMixin(Vue) // 添加 $nextTick, _render 函数 export default Vue

其中关键的就是this._init(options),它由initMixin(Vue)添加到Vue对象的原型上,在new Vue的最后调用,传入options

3. _init函数

文件位置:vue-dev/src/core/instance/init.js

Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// a uid
vm._uid = uid++
...
// merge options
if (options && options._isComponent) {
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options || {}, vm)
}
...
vm._self = vm
initLifecycle(vm) // 初始化vm
initEvents(vm) // 初始化 _events(清空), _hasHookEvent, listeners
initRender(vm) /* 初始化 _vnode, _staticTrees, $slots, $scopedSlots, _c, $createElement
使用defineReactive定义 vm 响应式的 $attrs, $listeners*/
callHook(vm, 'beforeCreate') // 调用beforeCreate钩子函数
initInjections(vm) // resolve injections before data/props
initState(vm) /* 依次初始化props, methods, data, computed, watch
initProps, initMethods, initData, initComputed, initWatch */
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created') // 调用created钩子函数
... if (vm.$options.el) {
vm.$mount(vm.$options.el)
/*
$mount在vue-dev/src/platforms/web/runtime/index.js处挂载, 调用了 return mountComponent(this, el, hydrating)
而mountComponent函数在vue-dev/src/core/instance/lifecycle.js处定义
主要完成以下步骤
1. callHook(vm, 'beforeMount') // 调用beforeMount钩子函数
2. new Watcher(vm, updateComponent, noop, { // 添加updateComponent的观察者
before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate') // 调用beforeUpdate钩子函数
}
}
}, true )
3. callHook(vm, 'mounted') // 调用mounted钩子函数
*/
}
}

initState(vm)详解

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)
}
}

在initState中,完成了props, methods, data, computed, watch的挂载(props>methods>data)

以其中的initData为例:

function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
// 判断是否为对象 Object.prototype.toString.call(obj) === '[object Object]'
...
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
let i = keys.length
while (i--) {
const key = keys[i]
...
proxy(vm, `_data`, key) // data中的属性代理到vm实例上去,这样就可以在vm实例中使用this.xx访问到data中的xx了
...
}
// observe data
observe(data, true /* asRootData */) // 为data添加观察者,这样修改就能触发更新
}

完~

vue 2.0源码学习笔记—new Vue ( Vue 初始化过程 )的更多相关文章

  1. Vue.js 源码学习笔记

    最近饶有兴致的又把最新版 Vue.js 的源码学习了一下,觉得真心不错,个人觉得 Vue.js 的代码非常之优雅而且精辟,作者本身可能无 (bu) 意 (xie) 提及这些.那么,就让我来吧:) 程序 ...

  2. 最新 Vue 源码学习笔记

    最新 Vue 源码学习笔记 v2.x.x & v3.x.x 框架架构 核心算法 设计模式 编码风格 项目结构 为什么出现 解决了什么问题 有哪些应用场景 v2.x.x & v3.x.x ...

  3. Underscore.js 源码学习笔记(下)

    上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...

  4. Underscore.js 源码学习笔记(上)

    版本 Underscore.js 1.9.1 一共 1693 行.注释我就删了,太长了… 整体是一个 (function() {...}());  这样的东西,我们应该知道这是一个 IIFE(立即执行 ...

  5. AXI_LITE源码学习笔记

    AXI_LITE源码学习笔记 1. axi_awready信号的产生 准备接收写地址信号 // Implement axi_awready generation // axi_awready is a ...

  6. Hadoop源码学习笔记(6)——从ls命令一路解剖

    Hadoop源码学习笔记(6) ——从ls命令一路解剖 Hadoop几个模块的程序我们大致有了点了解,现在我们得细看一下这个程序是如何处理命令的. 我们就从原头开始,然后一步步追查. 我们先选中ls命 ...

  7. Hadoop源码学习笔记(4) ——Socket到RPC调用

    Hadoop源码学习笔记(4) ——Socket到RPC调用 Hadoop是一个分布式程序,分布在多台机器上运行,事必会涉及到网络编程.那这里如何让网络编程变得简单.透明的呢? 网络编程中,首先我们要 ...

  8. RocketMQ 源码学习笔记————Producer 是怎么将消息发送至 Broker 的?

    目录 RocketMQ 源码学习笔记----Producer 是怎么将消息发送至 Broker 的? 前言 项目结构 rocketmq-client 模块 DefaultMQProducerTest ...

  9. RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?

    目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目结构 rocketmq-client 模块 DefaultMQProducerTest Roc ...

随机推荐

  1. 移动端 uni-app 滑动事件 精确判断手指滑动方向

    移动端根据手指滑动操作判断滑动方向 设计思路: 1.根据移动端touchstart和touchend方法获取手指触摸屏幕的开始坐标和结束坐标 2.根据两个坐标计算与水平方向的夹角 3.根据夹角判断当前 ...

  2. 浅析 Dapr 里的云计算设计模式

    Dapr 实际上是把分布式系统 与微服务架构实践的挑战以及k8s 这三个主题的全方位的设计组合,特别是Kubernetes设计模式 一书作者Bilgin Ibryam 提出的Multi-Runtime ...

  3. Kubernetes-kubectl介绍

    前言 本篇是Kubernetes第三篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战.本篇重要介绍kubectl的使用. Kubernetes系列文章: Kubernetes介绍 Kuber ...

  4. Powershell免杀从入门到实践

    转载https://www.jianshu.com/p/fb078a99e0d8 前言 文章首发于Freebuf 在之前发布的一篇 渗透技巧之Powershell实战思路 中,学习了powershel ...

  5. springMVC学习总结(一) --springMVC搭建

    springMVC学习总结(一) --springMVC搭建 搭建项目 1.创建一个web项目,并在项目中的src文件夹下创建一个包com.myl.controller. 2.添加相应jar包 3.在 ...

  6. pycharm 汉化

    1.首先进入pycharm,点击file,找到setting. 2.点击 plugins 搜索Chinese,找到Chinese(simplified)Language Pack EAP,点击inst ...

  7. Python常见问题 - python3 requests库提示警告InsecureRequestWarning的问题

    当使用 requests 库发送请求时报了以下警告 D:\python3.6\lib\site-packages\urllib3\connectionpool.py:847: InsecureRequ ...

  8. C# Dapper基本三层架构使用 (一、架构关系)

    Dapper是一款轻量级ORM工具.如果你在小的项目中,使用Entity Framework.NHibernate 来处理大数据访问及关系映射,未免有点杀鸡用牛刀.你又觉得ORM省时省力,这时Dapp ...

  9. CodeForce-811C Vladik and Memorable Trip(动态规划)

    Vladik and Memorable Trip CodeForces - 811C 有一个长度为 n 的数列,其中第 i 项为 ai. 现在需要你从这个数列中选出一些互不相交的区间,并且保证整个数 ...

  10. ECShop 文章添加缩略图功能

    为 ECShop 文章添加缩略图     ECShop 文章不包含缩略图比较遗憾,不过它的文章里包含一个附件上传,而且一般不会用到,这样,我们就可以改动一下,让它成为缩略图. 首先在 includes ...