new Vue时框架干了啥?

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)

    }

  }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容