当前位置: 首页>前端>正文

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)

? ? }

? }

}


https://www.xamrdz.com/web/2pg1848579.html

相关文章: