目录initState 状态初始化1. initProps2. initSetup3. initMethods4. initData5. initComputed 与 initWat
在配置标准化合并以及声明周期初始化完成之后,会调用 callHook('beforeCreate') 来表示组件已进入正式实例化阶段。
这个时候会对数据、方法、监听器等配置项进行对应的处理,并且在开发环境还会进行一系列校验,抛出校验异常信息。整个数据的初始化过程是 initInjection => initState => initProvide,但是 injection/provide 一般是一起使用,所以这里也替换一下顺序,将这两者放到后面一起分析。
首先是 initState 的函数定义:
export function initState(vm: Component) {
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
// Composition api
initSetup(vm)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
const ob = observe((vm._data = {}))
ob && ob.vmCount++
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
整个过程其实十分清晰:
该函数定义如下:
function initProps(vm: Component, propsOptions: Object) {
const propsData = vm.$options.propsData || {}
const props = (vm._props = shallowReactive({}))
const keys: string[] = (vm.$options._propKeys = [])
const isRoot = !vm.$parent
if (!isRoot) {
toggleObserving(false)
}
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
if (__DEV__) {
const hyphenatedKey = hyphenate(key)
if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) {
warn('')
}
defineReactive(props, key, value, () => {
if (!isRoot && !isUpdatinGChildComponent) {
warn('')
}
})
} else {
defineReactive(props, key, value)
}
if (!(key in vm)) {
proxy(vm, `_props`, key)
}
}
toggleObserving(true)
}
这个过程会遍历整个组件的 props 配置项(mergeOptions 之后,已包含继承和混入),并将每个 prop key 从驼峰形式转换为 - 短横线连接的形式。
这也是为什么官方推荐 props 配置使用 小写驼峰,而组件使用时绑定参数使用 - 短横线 的原因。
之后,则是校验每个 prop 的 key 是否符合规范(即不是 Vue 的内置关键字 ref,key 等,也是不是配置里面 isReservedAttr(key) 禁止的属性名);最后,通过 defineReactive 来对 prop 进行响应式处理,并挂载到 vm._props 中。
当然,上面的响应式处理 只针对根组件,如果不是根组件的话,是会在函数前面部分调用 toggleObserving(false) 来关闭响应式处理
这个部分是为了适配 v3 语法新增的一部分,这里就不放源码,只简单介绍一下。
该方法位于 src/v3/apiSetup.ts 文件内,在执行过程中,主要有以下几步:
函数定义如下:
function initMethods(vm: Component, methods: Object) {
const props = vm.$options.props
for (const key in methods) {
if (__DEV__) {
if (typeof methods[key] !== 'function') {
warn('')
}
if (props && hasOwn(props, key)) {
warn('')
}
if (key in vm && isReserved(key)) {
warn('')
}
}
vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
}
}
这部分就十分十分简单了,就是通过 Function.bind 函数来更改组件配置 options 中的每一个方法的 this 指向,最后重新绑定到当前组件上。
这里的校验其实就是校验名字是否会和 js 的内置方法名冲突,或者与 props 中存在同名方法。
在执行 initData 之前,会校验 options 中有没有 data 配置,没有则会初始化为一个空对象。
其函数定义如下:
function initData(vm: Component) {
let data: any = vm.$options.data
data = vm._data = isFunction(data) ? getData(data, vm) : data || {}
if (!isPlainObject(data)) {
data = {}
__DEV__ && warn('')
}
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
let i = keys.length
while (i--) {
const key = keys[i]
if (__DEV__) {
if (methods && hasOwn(methods, key)) {
warn('')
}
}
if (props && hasOwn(props, key)) {
__DEV__ && warn()
} else if (!isReserved(key)) {
proxy(vm, `_data`, key)
}
}
const ob = observe(data)
ob && ob.vmCount++
}
这里其实也比较简单,就是校验是否有与 props 或者 methods 同名的数据,并将其代理到 vm._data 上,最后通过 observe 方法对数据进行响应式处理。
这两部分主要是配置对 data 与 props 的变量的 变化侦测(监听) ,因为涉及到 Vue 的响应式系统中的 Watcher 观察者定义 与 依赖收集系统,整体的内容比较多,所以后面整体讲。
简单分析两者的基本逻辑:
initComputed:
initWatch:
这个过程则更加简单,因为不用校验 key 的重复性,所以会直接遍历 options.watch,如果某个属性的监听器有两个 handler 方法,还会将方法提出来,最后调用 createWatcher 来创建监听器。
到此这篇关于详解Vue 2中的 initState 状态初始化的文章就介绍到这了,更多相关Vue initState 内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: 详解Vue2中的 initState状态初始化
本文链接: https://www.lsjlt.com/news/165972.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-01-12
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0