1、传入options,调用Vue初始函数,如:
new Vue({
? ? data(){
? ? ? ? return {},
? ? }
}) ,时会调用Vue._init(options)方法。
2、_init方法会完成对生命周期、时间、渲染函数、state初始化,然后将vm挂载到el上,源码如下:
Step1: /vue/scr/core/instance/index.js
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)
}
Step2: /vue/src/core/instance/init.js
...
import { initState } from './state'
...
Vue.prototype._init = function(options:Object){
? ? const vm:Component = this; //将vm指向this
? ? //此处省去一些代码,对options做了一些判断
? ? vm._self = vm
? ? initLifecycle(vm) //初始化生命周期
? ? initEvents(vm) //初始化事件
? ? initRender(vm) //初始化渲染函数
? ? callHook(vm, 'beforeCreate') //执行beforeCreate 钩子
? ? initInjections(vm) // resolve injections before data/props
? ? initState(vm) //初始化数据观测
? ? initProvide(vm) // resolve provide after data/props
? ? callHook(vm, 'created') //执行created钩子
? ? if (vm.$options.el) {
? ? ? ? ? vm.$mount(vm.$options.el) //判定options中是否有el选项,如有则将vue挂载
? ? }
}
vue响应性是其最核心的功能,其中很重要的一个部分是实现对数据的监听,其中vue2.X是运用ES5 Object.defineProperty特性来进行数据监听的,为了便于理解,我们看如下范例:
var object = { name: "wh", age: "18" };
function defineReactive(object,key){
? var val = object[key];
? Object.defineProperty(object, key, {
? ? get() {
? ? ? console.log("set" + key);
? ? ? const value = val;
? ? ? return value;
? ? },
? ? set(newVal) {
? ? ? ? console.log("set" + key);
? ? ? ? val = newVal;
? ? },
? });
}
var keys = Object.keys(object);
for (var i=0;i<keys.length;i++) {
? defineReactive(object,keys[i]);
}
object.name = "kongzhi";
console.log(object.name);
object.age = "20";
console.log(object.age);
console.log(object.name);
运行后结果为:
setname
kongzhi
setage
20
kongzhi
通过上述代码运行,我们可以发现,运用Object.defineProperty对数据进行劫持后,每当调用数据则会触发get方法,而每当改变数据则会调用set方法。
VUE是通过对监听器、订阅器和订阅者的实现来实现响应性的,源码如下:
next Step1:/vue/src/core/instance/state.js
import {?
? set,
? del,
? observe,
? defineReactive,
? toggleObserving
} from /vue/src/core/observer/index
export function initState (vm: Component) {
? //vm 即为vue实例
? vm._watchers = []
? const opts = vm.$options
? if (opts.props) initProps(vm, opts.props)
? if (opts.methods) initMethods(vm, opts.methods)
? if (opts.data) {
? ? //若存在data 选项则执行initDate
? ? 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)
? }
}
function initData (vm: Component) {
? let data = vm.$options.data
? //data选项类型是否为function,禁止订阅器订阅
? data = vm._data = typeof data === 'function'
? ? ? getData(data, vm)
? ? : data || {}
? if (!isPlainObject(data)) {
? ? data = {}
? ? process.env.NODE_ENV !== 'production' && warn(
? ? ? 'data functions should return an object:\n' +
? ? ? 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
? ? ? vm
? ? )
? }
? // proxy data on instance
? const keys = Object.keys(data)
? const props = vm.$options.props
? const methods = vm.$options.methods
? let i = keys.length
? //判定data 和 methods、props 选项是否重名,若存在重名则抛出警告。
? while (i--) {
? ? const key = keys[i]
? ? if (process.env.NODE_ENV !== 'production') {
? ? ? if (methods && hasOwn(methods, key)) {
? ? ? ? warn(
? ? ? ? ? `Method "${key}" has already been defined as a data property.`,
? ? ? ? ? vm
? ? ? ? )
? ? ? }
? ? }
? ? if (props && hasOwn(props, key)) {
? ? ? process.env.NODE_ENV !== 'production' && warn(
? ? ? ? `The data property "${key}" is already declared as a prop. ` +
? ? ? ? `Use prop default value instead.`,
? ? ? ? vm
? ? ? )
? ? } else if (!isReserved(key)) {
? ? ? proxy(vm, `_data`, key)
? ? }
? }
? // 重点:调用observe函数对data进行监听
? observe(data, true /* asRootData */)
}
next Step2:/vue/src/coreobserver/index.js
export function observe (value: any, asRootData: ?boolean): Observer | void {
? if (!isObject(value) || value instanceof VNode) {
? ? return
? }
? let ob: Observer | void
? if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
? ? ob = value.__ob__
? } else if (
? ? shouldObserve &&
? ? !isServerRendering() &&
? ? (Array.isArray(value) || isPlainObject(value)) &&
? ? Object.isExtensible(value) &&
? ? !value._isVue
? ) {
? ? //若data未被监听,则添加监听器
? ? ob = new Observer(value)
? }
? if (asRootData && ob) {
? ? ob.vmCount++
? }
? return ob
}
//监听器类
export class Observer {
? value: any;
//监听器
? dep: Dep;
? vmCount: number; // number of vms that have this object as root $data
? constructor (value: any) {
? ? this.value = value
? ? //初始化观测器
? ? this.dep = new Dep()
? ? this.vmCount = 0
? ? //为data添加__ob__属性
? ? def(value, '__ob__', this)
? //实现数组监听
? ? if (Array.isArray(value)) {
? ? ? if (hasProto) {
? ? ? ? protoAugment(value, arrayMethods)
? ? ? } else {
? ? ? ? copyAugment(value, arrayMethods, arrayKeys)
? ? ? }
? ? ? this.observeArray(value)
? ? } else {
? ? ? //实现对象监听
? ? ? this.walk(value)
? ? }
? }
? /**
? * Walk through all properties and convert them into
? * getter/setters. This method should only be called when
? * value type is Object.
? */
? walk (obj: Object) {
? ? const keys = Object.keys(obj)
? ? for (let i = 0; i < keys.length; i++) {
? ? ? //遍历data对象属性,添加监听器
? ? ? defineReactive(obj, keys[i])
? ? }
? }
}
/**
* Define a reactive property on an Object.
*/
export function defineReactive (
? obj: Object,
? key: string,
? val: any,
? customSetter?: ?Function,
? shallow?: boolean
) {
? //初始化订阅器
? const dep = new Dep()
//...省略一堆代码
//若值为对象则递归添加监听器
? let childOb = !shallow && observe(val)
? Object.defineProperty(obj, key, {
? ? enumerable: true,
? ? configurable: true,
? ? get: function reactiveGetter () {
? ? ? const value = getter ? getter.call(obj) : val
? ? ? if (Dep.target) {
? ? ? ? //若数据被调用,则订阅者者收集订阅器
? ? ? ? dep.depend()
? ? ? ? if (childOb) {
? ? ? ? ? childOb.dep.depend()
? ? ? ? ? if (Array.isArray(value)) {
? ? ? ? ? ? dependArray(value)
? ? ? ? ? }
? ? ? ? }
? ? ? }
? ? ? return value
? ? },
? ? set: function reactiveSetter (newVal) {
? ? ? const value = getter ? getter.call(obj) : val
? ? ? /* eslint-disable no-self-compare */
? ? ? if (newVal === value || (newVal !== newVal && value !== value)) {
? ? ? ? return
? ? ? }
? ? ? /* eslint-enable no-self-compare */
? ? ? if (process.env.NODE_ENV !== 'production' && customSetter) {
? ? ? ? customSetter()
? ? ? }
? ? ? // #7981: for accessor properties without setter
? ? ? if (getter && !setter) return
? ? ? if (setter) {
? ? ? ? setter.call(obj, newVal)
? ? ? } else {
? ? ? ? val = newVal
? ? ? }
? ? //若数据被修改,则对新数据重新添加观测器
? ? ? childOb = !shallow && observe(newVal)
? ? //调用监听器notify方法
? ? ? dep.notify()
? ? }
? })
}
next Step2:/vue/src/core/observer/dep.js
export default class Dep {
? static target: ?Watcher;
? id: number;
? subs: Array<Watcher>;
? constructor () {
? ? this.id = uid++
? ? this.subs = []
? }
? //监听器可以实现对监听者添加和删除
? addSub (sub: Watcher) {
? ? this.subs.push(sub)
? }
? removeSub (sub: Watcher) {
? ? remove(this.subs, sub)
? }
? depend () {
? ? if (Dep.target) {
? ? ? Dep.target.addDep(this)
? ? }
? }
? //当数据被修改,调用notify方法
? notify () {
? ? // stabilize the subscriber list first
? ? const subs = this.subs.slice()
? ? if (process.env.NODE_ENV !== 'production' && !config.async) {
? ? ? // subs aren't sorted in scheduler if not running async
? ? ? // we need to sort them now to make sure they fire in correct
? ? ? // order
? ? ? subs.sort((a, b) => a.id - b.id)
? ? }
? ? for (let i = 0, l = subs.length; i < l; i++) {
? ? ? //循环遍历监听者,调用监听者update()方法
? ? ? subs[i].update()
? ? }
? }
}
next Step3:/vue/src/core/observer/watcher.js
? update () {
? ? /* istanbul ignore else */
? ? if (this.lazy) {
? ? ? this.dirty = true
? ? } else if (this.sync) {
? ? ? //若为异步则调用run方法
? ? ? this.run()
? ? } else {
? ? ? queueWatcher(this)
? ? }
? }
? /**
? * Scheduler job interface.
? * Will be called by the scheduler.
? */
? run () {
? ? if (this.active) {
? ? ? const value = this.get()
? ? ? if (
? ? ? ? value !== this.value ||
? ? ? ? // Deep watchers and watchers on Object/Arrays should fire even
? ? ? ? // when the value is the same, because the value may
? ? ? ? // have mutated.
? ? ? ? isObject(value) ||
? ? ? ? this.deep
? ? ? ) {
? ? ? ? // set new value
? ? ? ? const oldValue = this.value
? ? ? ? this.value = value
? ? ? ? if (this.user) {
? ? ? ? ? try {
? ? ? ? ? ? //触发监听者回调函数更新视图
? ? ? ? ? ? this.cb.call(this.vm, value, oldValue)
? ? ? ? ? } catch (e) {
? ? ? ? ? ? handleError(e, this.vm, `callback for watcher "${this.expression}"`)
? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? //触发监听者回调函数更新视图
? ? ? ? ? this.cb.call(this.vm, value, oldValue)
? ? ? ? }
? ? ? }
? ? }
? }
next Step4:/vue/src/core/observer/scheduler.js
import { queueWatcher } from './scheduler'
export const MAX_UPDATE_COUNT = 100
const queue: Array<Watcher> = []
const activatedChildren: Array<Component> = []
let has: { [key: number]: ?true } = {}
let circular: { [key: number]: number } = {}
let waiting = false
let flushing = false
let index = 0
export function queueWatcher (watcher: Watcher) {
? const id = watcher.id
? if (has[id] == null) {
? ? //判断监听者id是否存在,若不存在,则加入has
? ? has[id] = true
? ? if (!flushing) {
? ? ? //若还未刷新则将监听者加入队列
? ? ? queue.push(watcher)
? ? } else {
? ? ? // if already flushing, splice the watcher based on its id
? ? ? // if already past its id, it will be run next immediately.
? ? ? let i = queue.length - 1
? ? ? while (i > index && queue[i].id > watcher.id) {
? ? ? ? i--
? ? ? }
? ? 将最后一个监听者替换此前监听者
? ? ? queue.splice(i + 1, 0, watcher)
? ? }
? ? // queue the flush
? ? if (!waiting) {
? ? ? waiting = true
? ? ? if (process.env.NODE_ENV !== 'production' && !config.async) {
? ? ? ? flushSchedulerQueue()
? ? ? ? return
? ? ? }
? ? ? nextTick(flushSchedulerQueue)
? ? }
? }
}