vue源码分析(1)

vue用得也有点久了,现在想去看看vue框架是怎么创造出来的,加深我对vue的印象。
ts基础没有的理解下就OK,百度10分钟就可以理解了。
1
2
3
4
5
6
7
8
9
10
11
import { initMixin } from './init.js'

class Vue {
constructor(options){
this._init(options) //放在了原型链上了
}
}

initMixin(Vue)

export default Vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//init.js
const uid = 0

export function initMixin (Vue: Class<component>/*ts*/){
Vue.prototype._init = function (options?:Object){
const vm: Component = this
vm._uid = uid++

vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
) //这里是为vue实例添加option 例如vue.$options.el https://vuefe.cn/v2/api/#vm-options

initState(vm)

}
}
1
2
3
4
5
6
7
8
9
10
11
//state.js
import { bind } from '../util/index'


export function initState (vm: Component) {
const opts = vm.$options
if (opts.methods) initMethods(vm, opts.methods) //初始化methods
if (opts.data) {
initData(vm) //直接存vm么?
}
}

methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//258  state.js  
function initMethods (vm: Component,methods: Object){
const props = vm.$options.props
for (const key in methods){
if (methods[key] == null) {
warn(
`Method "${key}" has an undefined value in the component definition. ` +
`Did you reference the function correctly?`,
vm
)
}

if(props && hasOwn(props, key) ){
warn(`Method "${key}" has already been defined as a prop.`, vm)
//props = [] 嗯 知道了不能props 和 methods的方法名不能同时存在,就是我平时组件的时候
//可以this.method吧 而不是像data那样 this.$data.data (冲突的时候的话,嘛我猜的,到时候看到这就OK了)

}

if((key in vm) && isReserved(key)){
warn(
`Method "${key}" conflicts with an existing Vue instance method. ` +
`Avoid defining component methods that start with _ or $.`
)
//不能定义vue自带的方法
}

vm[key] = bind(methods[key], vm)
//你传进来的options.methods的方法,this就被绑定在这个vue实例上了

}


}

util包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//shared/util.js

function nativeBind (fn: Function, ctx: Object): Function {
return fn.bind(ctx)
}

export const bind = Function.prototype.bind
? nativeBind
: polyfillBind

export function isPlainObject (obj: any): boolean { //58
return _toString.call(obj) === '[object Object]'
//直接转换字符串 来判断 Object.is()
}

export function isObject (obj: mixed): boolean %checks { //41
return obj !== null && typeof obj === 'object'
}



//所有继承了 Object 的对象都会继承到 hasOwnProperty 方法。
//这个方法可以用来检测一个对象是否含有特定的自身属性;和 in 运算符不同
//该方法会忽略掉那些从原型链上继承到的属性。
const hasOwnProperty = Object.prototype.hasOwnProperty
export function hasOwn (obj: Object | Array<*>, key: string): boolean {
return hasOwnProperty.call(obj, key)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//core/util/env.js  37
// this needs to be lazy-evaled because vue may be required before
// vue-server-renderer can set VUE_ENV
/*const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
在webpack.server.js 当作一个插件 生成server.json 可以去看SSR文章
*/
let _isServer
export const isServerRendering = () => {
if (_isServer === undefined) {
/* istanbul ignore if */
if (!inBrowser && !inWeex && typeof global !== 'undefined') {
// detect presence of vue-server-renderer and avoid
// Webpack shimming the process
_isServer = global['process'].env.VUE_ENV === 'server'
} else {
_isServer = false
}
}
return _isServer
}

lang

1
2
3
4
export function isReserved (str: string): boolean {
const c = (str + '').charCodeAt(0) //utf-16 编码
return c === 0x24 || c === 0x5F // $ 36 0044 0x24 ; _ 95 0137 0x5f
}

data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 112  state.js
function initData (vm: Component){
let data = vm.$options.data
data = vm._data = typeof data === 'function' //组件data() 未分析到 留下
? getData(data,vm)
: data || {} //我觉得这默认值没有必要

if(!isPlainObject(data)){ //data不是Object 将报错 Object.is()也可以
data = {}
warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
)
}

//prop methods 与 data的key 的冲突err
const keys = Obejct.keys(data) //数组 含有iterator 可以用for of
const props = vm.$options.props
const methods = vm.$options.methods
for( let {i, value} of keys ){ //具名匹配
if(methods && hasOwn(methods, key)){ //methods冲突
warn( //warning 是dev的
`Method "${key}" has already been defined as a data property.`,
vm
)
}
if (props && hasOwn(props, key)) {
warn( //warning 是dev的
`The data property "${key}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
)
} else if (!isReserved(key)) { //当不是$ 或者 _的时候
proxy(vm, `_data`, key)// vm去拿data里面的某个key的时候,将在vm._data.key取
//例如平时我们不是在内部 this.key 那样取到的嘛 就是通过这个方法实现的
}
}
// observe data
observe(data, true /* asRootData */)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//state.js 31


const sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
}

//state.js 38
export function proxy (target: Object, sourceKey: string, key: string) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
}
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val
}
Object.defineProperty(target, key, sharedPropertyDefinition)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export let shouldObserve: boolean = true
//core/observer/index.js 109
分析Observer
export function observe (value: any, asRootData: ?boolean): Observer | void /*返回Observer 或无*/{
if(!isObject(value)){
return
}
let ob: Obeserver | void
if(hasOwn(value, '__ob__') && value.__ob__ instanceof Observer){ //这干嘛?data里面有__ob__??谁添加进去的?
ob = value.__ob__

}else if(
shouldObserve &&
!isServerRendering()/*判断是不是 不是SSR*/ &&
(Array.isArray(value) || isPlainObject(value)) &&
)




}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//core/observer/index.js   37
export class Observer {
value: any; //这些是ts里面的那些实例属性,记住分号
dep: Dep; //简称实例属性
vmCount: number;

constructor (value: any){
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__',this)
if(Array.isArray(value)){
const augment = hasProto
? protoAugment
: copyAugment

augemnt(value, arrayMethods, arrayKeys)
this.observeArray(value)

} else {
this.walk(value)
}


}



}
文章目录
  1. 1. methods
  2. 2. util包
  3. 3. lang
  4. 4. data
|