VueJS学习之旅 07

下面我就来看看Vue的核心构造器以及其实例的属性和方法。


Vue构造器

从 'src/core/index.js' 文件中可以找到Vue构造器的定义是在 'src/core/instance/index.js' 中给出的。
打开该文件,我们来看看代码。

// src/core/instance/index.js

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
  • 非常简短,该构造器接收一个对象类型的 options 参数。
  • 初始化Vue实例对象时,默认调用原型对象上的 _init (Vue.prototype._init) 方法。

该文件中还通过调用一些模块,给Vue增加了一些实例方法。

  • 与数据相关的方法:$set, $delete, $watch
  • 与事件相关的方法:$on, $once, $off, $emit
  • 与生命周期相关的方法:$forceUpdate, $destroy
  • 还有一个与生命周期相关的方法 $mount 是在entiry文件(如: 'src/entries/web-runtime-with-compiler.js')中定义的。

以上的这些方法,就是对应官方API中实例方法。

Vue实例对象方法

结合官方API文档和源码,具体来看看这些实例方法。

实例方法 / 数据相关

  • vm.$watch

    对应方法源码 src/core/instance/state.js => Vue.prototype.$watch

    1. 该方法内部新建一个Watcher实例,并将其添加到当前Vue实例对象的 _watchers 列表中。
    2. 方法返回值是一个撤销观察函数 unwatch。如需撤销观察,只需执行 unwatch();
  • vm.$set

    对应方法源码 src/core/instance/state.js => Vue.prototype.$set

    1. 从代码可见,这是Global API中 Vue.set 的别名。
  • vm.$delete

    对应方法源码 src/core/instance/state.js => Vue.prototype.$delete

    1. 从代码可见,这是Global API中 Vue.delete 的别名。

实例方法 / 事件相关

  • vm.$on

    对应方法源码 src/core/instance/events.js => Vue.prototype.$on

    1. Vue实例对象 vm 中有 _events 属性,用来记录事件的注册信息
    2. 如果 vm 中已有 event 事件注册过,则向该事件注册列表中添加callback处理器;如果没有相关事件注册过,则先行初始化该事件注册列表,再将callback注册到列表中。
    3. 如果 event 是 hook 事件,则将 vm_hasHookEvent 属性设置为 true
    4. 执行结果返回 vm
  • vm.$off

    对应方法源码 src/core/instance/events.js => Vue.prototype.$off

    1. 如果没有传递参数,默认将 vm_events 清空,然后返回当前实例对象。相当于注销所有事件注册。
    2. 如果 vm 还没有注册过 event 事件,直接返回 vm
    3. 如果只提供了 event,则移除该事件所有的监听器
    4. 如果同时提供了 eventcallback,则获取该 event 的注册列表,遍历列表将给定的 callback 监听器注销。
  • vm.$once

    对应方法源码 src/core/instance/events.js => Vue.prototype.$once

    1. 分别调用 $on$off 来完成事件的注册和注销。
    2. 只执行一次,执行后立即移除监听器。
  • vm.$emit

    对应方法源码 src/core/instance/events.js => Vue.prototype.$emit

    1. 获取 vmevent 的注册列表
    2. 遍历注册列表中的所有处理器,依次调用

实例方法 / 生命周期相关

  • vm.$forceUpdate

    对应方法源码 src/core/instance/lifecycle.js => Vue.prototype.$forceUpdate

    1. 如果当前实例对象存在 _watcher 属性,执行 _watcherupdate 方法。
  • vm.$destroy

    对应方法源码 src/core/instance/lifecycle.js => Vue.prototype.$destroy

    1. Vue实例对象 vm 如果被标记为正在销毁(_isBeingDestroyed == true),则直接返回,避免重复调用。
    2. 调用 'beforeDestroyed' 生命周期事件处理函数。
    3. _isBeingDestroyed 属性标记为 true。
    4. 清除父对象中的信息
    5. 清除watchers
    6. 清除当前对象的数据监听(observer)
    7. 调用 'destroyed' 生命周期事件处理函数。
    8. 清除所有注册的事件监听
    9. 触发视图更新
  • vm.$nextTick

    对应方法源码 src/core/instance/render.js => Vue.prototype.$nextTick

    1. 代码执行与 Vue.nextTick 一样,只不过方法执行的句柄(this)自动邦定到当前的Vue实例对象。
  • vm.$mount

    对应方法源码 src/entries/web-runtime-with-compiler.js => Vue.prototype.$mount

    1. 该方法实际上调用的是 Vue.prototype._mount 方法,定义在 'src/core/instance/lifecycle.js' 文件中。
    2. 如果实例对象 vm 中没有给定 render ,则将 'createEmptyVNode' 赋值给 'render'。
    3. 调用 'beforeMount' 生命周期事件处理函数。
    4. vm 增加watcher。
    5. 调用 'mounted' 生命周期事件处理函数。
    6. 返回 vm 实例对象。

Vue对象实例的属性

有关于Vue实例属性的初始化,基本上是调用 Vue.prototype._init 方法中完成的。上面提到过这个方法会在new Vue(options) 时自动调用。
这个方法定义在 'src/core/instance/init.js' 文件中,简要地看看它都做了什么。

  1. 初始化 vm.$options,主要是调用 mergeOptions 方法,将构造器的默认属性与给定的options合并后赋值为 vm.$options
  2. 初始化生命周期相关的属性,给 vm.$parent, vm.$root, vm.$children, vm.$refs 等属性赋值。
  3. 初始化 vm 事件监听,将父组件事件更新到当前对象
  4. 调用 'beforeCreate' 生命周期事件处理函数
  5. 初始化与data相关的属性,这里面有一步重要的操作,就是observe数据(vm._data,vm.$data就是对该对象的代理)。这会创建Observer对象并调用 defineReactive 函数,这是Vue实现双向数据邦定的基础。具体请参照 defineReactive 函数以及JS属性描述符相关资料。
  6. 调用 'created' 生命周期事件处理函数
  7. 初始化 render 相关的属性:$slots, $scopedSlots等。

结合官方API文档和源码,具体来看看这些实例属性的含义以及他们是如何赋初值的。

  • vm.$data

    Vue 实例观察的数据对象。Vue 实例代理了对其 data 对象属性的访问。

    1. 该属性不是直接定义在实例对象 vm 上,而是定义在原型对象上 => Vue.prototype.$data
    2. 该属性是只读属性,不能直接给该属性重新赋值。但可以set其内部具体的内嵌属性。
    3. 个人理解,就是应为要定义为只读属性,所以在定义在prototype对象上。
  • vm.$el

    Vue 实例使用的根 DOM 元素。

    1. 该属性不是在初始化时设置的,而是在调用 Vue.prototype._mountue.prototype._update 时才赋值的。
  • vm.$options

    用于当前 Vue 实例的初始化选项。需要在选项中包含自定义属性时会有用处

    1. 当初始化实例对象时,通过执行 Vue.prototype._init 方法时赋值的。构造器的默认属性与给定的options合并后赋值给它。
  • vm.$parent

    父实例,如果当前实例有的话。

    1. 当初始化实例对象时,通过执行 Vue.prototype._init 方法时赋值的。
  • vm.$root

    当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自已。

    1. 当初始化实例对象时,通过执行 Vue.prototype._init 方法时赋值的。
  • vm.$children

    当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。

    1. 当初始化实例对象时,通过执行 Vue.prototype._init 方法时赋值的。
  • vm.$slots

    用来访问被 slot 分发的内容。每个具名 slot 有其相应的属性(例如:slot="foo" 中的内容将会在 vm.$slots.foo 中被找到)。default 属性包括了所有没有被包含在具名 slot 中的节点。
    在使用 render 函数书写一个组件时,访问 vm.$slots 最有帮助。

    1. 当初始化实例对象时,通过执行 Vue.prototype._init 方法时赋值的。
  • vm.$scopedSlots

    用来访问被 scoped slots。包括 default 在内的每个 slot,对象内都包含一个返回 VNodes 的函数。
    在使用 render 函数书写一个组件时,访问 vm.$slots 最有帮助。

    1. 当初始化实例对象时,通过执行 Vue.prototype._init 方法时赋值的。
  • vm.$refs

    一个对象,其中包含了所有拥有 ref 注册的子组件。

    1. 当初始化实例对象时,通过执行 Vue.prototype._init 方法时赋值的。
  • vm.$isServer

    当前 Vue 实例是否运行于服务器。

    1. 该属性不是直接定义在实例对象 vm 上,而是定义在原型对象上 => Vue.prototype.$isServer
    2. 该属性根据当前运行的环境以及 process.ven.VUE_ENV 自动设置。

你可能感兴趣的:(VueJS学习之旅 07)