免费网站备案号码,做网站原型图,河北3市最新任免,建设银行官方网站手机版例子1new Vue做了啥?new Vue做了啥,源码解析 initMixin函数 初始化 – 初始化Vue实例的配置initLifecycle函数 – 初始化生命周期钩子函数initEvents – 初始化事件系统初始化渲染 initRender初始化inject选项 例子1
div idappdiv classhomediv idappdiv classhomeh1{{title}}/h1/div
/divnew Vue({el: #app,data: () {return {title: Home Page}}
})更多详细内容请微信搜索“前端爱好者“ 戳我 查看 。
new Vue()做了啥?
在Vue.js 2.x的源码中new Vue()的主要作用是创建一个Vue实例。当我们调用new Vue()时会经过以下几个步骤
初始化Vue实例的配置Vue会将我们传入的配置对象进行初始化包括数据、计算属性、方法等。初始化生命周期钩子函数Vue会在初始化过程中执行一系列的生命周期钩子函数例如beforeCreate、created、beforeMount、mounted等。初始化事件系统Vue会为实例创建一个事件总线用于处理事件的监听和触发。解析模板如果配置中指定了template选项Vue会将模板解析成渲染函数以便后续的渲染过程中使用。初始化渲染Vue会创建一个虚拟DOM并将之前解析的渲染函数进行渲染生成真实DOM并将其挂载到页面上。数据响应式处理Vue会对实例中的数据进行响应式处理即通过劫持数据的访问和修改实现数据的双向绑定。
在这个过程中Vue还会做很多其他的工作例如处理指令、组件注册、依赖收集等以确保整个应用的正常运行和响应式更新。
以上只是对new Vue()的简单概述具体的实现细节涉及到很多源码内容在Vue.js的源码中可以详细了解其中的实现原理。
new Vue()做了啥,源码解析
vue源码版本vue2.5.2
new Vue()会执行_init方法而_init方法在initMixin函数中定义。
src/core/instance/index.js文件中定义了Vue
function Vue (options) {this._init(options)
}initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)export default VueinitMixin函数 初始化 – 初始化Vue实例的配置
const vm: Component this定义vm等于Vue;vm._uid uid; vm存在_uid自增vm._isVue true只有是经过vue实例化的。vm都存在_isVue属性为true值options options._isComponent 当options存在_isComponent属性时执行initInternalComponent(vm, options)当组件options._isComponen不存在时执行 mergeOptions( resolveConstructorOptions(vm.constructor), options || {},vm )m._renderProxy vm给vm定义一个_renderProxy 属性等于自身vm._self vm给vm定义一个_self 属性等于自身initLifecycle(vm)初始化生命周期相关实例属性initEvents(vm)初始化事件initRender(vm)定义$createElement() createElement的执行过程callHook(vm, ‘beforeCreate’)执行beforeCreate生命周期钩子initInjections(vm)initState(vm)将data代理至Vue._data data的代理initProvide(vm)初始化providecallHook(vm, ‘created’)执行created生命周期钩子vm. m o u n t ( v m . mount(vm. mount(vm.options.el)执行挂载
定义的 Vue.prototype._init export function initMixin (Vue: ClassComponent) {Vue.prototype._init function (options?: Object) {const vm: Component this// a uid自增IDvm._uid uidvm._isVue true// merge options 合并optionsif (options options._isComponent) {initInternalComponent(vm, options)} else {vm.$options mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}vm._renderProxy vm// expose real selfvm._self vm// 初始化生命周期相关实例属性initLifecycle(vm)//初始化事件initEvents(vm)//定义$createElement() createElement的执行过程initRender(vm)// 执行beforeCreate生命周期钩子callHook(vm, beforeCreate)initInjections(vm) // resolve injections before data/props//将data代理至Vue._data data的代理initState(vm)// 初始化provideinitProvide(vm) // resolve provide after data/props// 执行created生命周期钩子callHook(vm, created)// 当options中存在el属性则执行挂载if (vm.$options.el) {//挂载#app $mount执行过程vm.$mount(vm.$options.el)}}
}initLifecycle函数 – 初始化生命周期钩子函数
initLifecycle 初始化生命周期相关变量即在vue实例上挂载一些属性并设置默认值如 p a r e n t , parent, parent,root,$children,$ref,vm._watcher,vm.__inactive,vm._directInactive,vm._isMounted,vm._isDestroyed,vm._isBeingDestroyed
export function initLifecycle (vm: Component) {const options vm.$options// locate first non-abstract parentlet parent options.parent//当前组件存在父级并且当前组件不是抽象组件if (parent !options.abstract) {//通过while循环来向上循环如果当前组件的父级是抽象组件并且也存在父级那就继续向上查找当前组件父级的父级while (parent.$options.abstract parent.$parent) {//更新parentparent parent.$parent}//把该实例自身添加进找到的父级的$children属性中parent.$children.push(vm)}//直到找到第一个不是抽象类型的父级时将其赋值vm.$parentvm.$parent parent//设置实例根元素。判断如果当前实例存在父级那么当前实例的根实例$root属性就是其父级的根实例$root属性如果不存在那么根实例$root属性就是它自己vm.$root parent ? parent.$root : vmvm.$children []vm.$refs {}vm._watcher nullvm._inactive nullvm._directInactive false//实例是否已挂载vm._isMounted false//实例是否已销毁vm._isDestroyed false//实例是否正准备销毁vm._isBeingDestroyed false
}合并options之后 initEvents – 初始化事件系统
initEvents 初始化事件。 初始化的是父组件在模板中使用v-on或注册的监听子组件内触发的事件。
export function initEvents (vm: Component) {
//在vm上新增_events属性并将其赋值为空对象用来存储事件。vm._events Object.create(null)vm._hasHookEvent false// init parent attached events//获取父组件注册的事件赋给listenersconst listeners vm.$options._parentListeners//如果listeners不为空则调用updateComponentListeners函数将父组件向子组件注册的事件注册到子组件的实例中if (listeners) {updateComponentListeners(vm, listeners)}
}初始化渲染 initRender
initRender函数 初始化渲染.。
export function initRender (vm: Component) {vm._vnode null // the root of the child treevm._staticTrees null // v-once cached treesconst options vm.$optionsconst parentVnode vm.$vnode options._parentVnode // the placeholder node in parent treeconst renderContext parentVnode parentVnode.context//实例上插槽vm.$slots resolveSlots(options._renderChildren, renderContext)vm.$scopedSlots emptyObject//在实例上定义_c函数和$_createElement函数vm._c (a, b, c, d) createElement(vm, a, b, c, d, false)vm.$createElement (a, b, c, d) createElement(vm, a, b, c, d, true)const parentData parentVnode parentVnode.datadefineReactive(vm, $attrs, parentData parentData.attrs || emptyObject, null, true)defineReactive(vm, $listeners, options._parentListeners || emptyObject, null, true)}初始化inject选项
inject 选项中的每一个数据key都是由其上游父级组件提供的所以我们应该把每一个数据key从当前组件起不断的向上游父级组件中查找该数据key对应的值直到找到为止。
如果在上游所有父级组件中没找到那么就看在inject 选项是否为该数据key设置了默认值如果设置了就使用默认值如果没有设置则抛出异常。
export function initInjections (vm: Component) {
//调用resolveInject把inject选项中的数据转化成键值对的形式赋给resultconst result resolveInject(vm.$options.inject, vm)if (result) {toggleObserving(false)//遍历result中的每一对键值Object.keys(result).forEach(key {//调用defineReactive函数将其添加当前实例上defineReactive(vm, key, result[key])})toggleObserving(true)}
}注意在把result中的键值添加到当前实例上之前会先调用toggleObserving(false)而这个函数内部是把shouldObserve false这是为了告诉defineReactive函数仅仅是把键值添加到当前实例上而不需要将其转换成响应式
resolveInject函数内部是如何把inject 选项中数据转换成键值对的。
export function resolveInject (inject: any, vm: Component): ?Object {if (inject) {// inject is :any because flow is not smart enough to figure out cached//创建一个空对象result用来存储inject 选项中的数据key及其对应的值作为最后的返回结果。const result Object.create(null)const keys hasSymbol? Reflect.ownKeys(inject).filter(key {/* istanbul ignore next */return Object.getOwnPropertyDescriptor(inject, key).enumerable}): Object.keys(inject)for (let i 0; i keys.length; i) {const key keys[i]//provideKey就是上游父级组件提供的源属性const provideKey inject[key].fromlet source vm//while循环从当前组件起不断的向上游父级组件的_provided属性中父级组件使用provide选项注入数据时会将注入的数据存入自己的实例的_provided属性中查找直到查找到源属性的对应的值将其存入result中while (source) {if (source._provided hasOwn(source._provided, provideKey)) {result[key] source._provided[provideKey]break}source source.$parent}if (!source) {//是否有default属性如果有的话则拿到这个默认值官方文档示例中说了默认值可以为一个工厂函数所以当默认值是函数的时候就去该函数的返回值否则就取默认值本身。如果没有设置默认值则抛出异常。if (default in inject[key]) {const provideDefault inject[key].defaultresult[key] typeof provideDefault function? provideDefault.call(vm): provideDefault} else if (process.env.NODE_ENV ! production) {warn(Injection ${key} not found, vm)}}}return result}
}官方文档中说inject 选项可以是一个字符串数组也可以是一个对象在上面的代码中只看见了处理当为对象的情况那如果是字符串数组呢怎么没有处理呢
其实在初始化阶段_init函数在合并属性的时候还调用了一个将inject 选项数据规范化的函数normalizeInject
参考文档
https://blog.csdn.net/weixin_40119412/article/details/128880336