今天我们来解密下init.ts中的代码内容,并结合 vue 生命周期来分析下 vue 的初始化;

import config from '../config'
import { initProxy } from './proxy'
import { initState } from './state'
import { initRender } from './render'
import { initEvents } from './events'
import { mark, measure } from '../util/perf'
import { initLifecycle, callHook } from './lifecycle'
import { initProvide, initInjections } from './inject'
import { extend, mergeOptions, formatComponentName } from '../util/index'
import type { Component } from 'types/component'
import type { InternalComponentOptions } from 'types/options'
import { EffectScope } from 'v3/reactivity/effectScope'
// vue 实例id
let uid = 0
export function initMixin(Vue: typeof Component) {
// 接收实例化传入的参数
Vue.prototype._init = function (options?: Record<string, any>) {
//vue 实例
const vm: Component = this
// 每个vue实例都有对应的一个实例id
vm._uid = uid++
let startTag, endTag
/* istanbul ignore if */
// 代码覆盖率测试
if (__DEV__ && config.performance && mark) {
startTag = `vue-perf-start:${vm._uid}`
endTag = `vue-perf-end:${vm._uid}`
mark(startTag)
}
// a flag to mark this as a Vue instance without having to do instanceof
// check
// 标记作为vue的实例不必去执行instanceof
vm._isVue = true
// avoid instances from being observed
// 避免实例被observed观察
vm.__v_skip = true
// effect scope
// https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md
// 对内部的响应式对象的副作用effect进行统一管理
vm._scope = new EffectScope(true /* detached */)
vm._scope._vm = true
// merge options
// 合并参数
// 判断是否是子组件
if (options && options._isComponent) {
// optimize internal component instantiation
// 优化内部组件实例化
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
// 由于动态选项合并非常缓慢,并且没有一个内部组件选项需要特殊处理。
// 传入vue实例并进行组件初始化
initInternalComponent(vm, options as any)
} else {
// 根组件配置 | 合并参数
vm.$options = mergeOptions(
// 解析构造函数参数
resolveConstructorOptions(vm.constructor as any),
options || {},
vm
)
}
/* istanbul ignore else */
// 代码覆盖测试
if (__DEV__) {
initProxy(vm)
} else {
vm._renderProxy = vm
}
// expose real self
vm._self = vm
// 核心的核心
// 初始化生命周期
initLifecycle(vm)
// 初始化事件监听
initEvents(vm)
// 初始化渲染
initRender(vm)
// 调用生命周期的钩子函数 | beforeCreate
callHook(vm, 'beforeCreate', undefined, false /* setContext */)
// https://v2.cn.vuejs.org/v2/api/#provide-inject
// 在data/props前进行inject
initInjections(vm) // resolve injections before data/props
initState(vm)
// https://v2.cn.vuejs.org/v2/api/#provide-inject
// provide 父组件提供的数据
// inject 子组件进行注入后直接使用
// 在data/props后进行provide
initProvide(vm) // resolve provide after data/props
// 调用生命周期钩子函数 | created
callHook(vm, 'created')
/* istanbul ignore if */
// 代码覆盖测试
if (__DEV__ && config.performance && mark) {
vm._name = formatComponentName(vm, false)
mark(endTag)
measure(`vue ${vm._name} init`, startTag, endTag)
}
// 组件如果设置了el则挂载到指定的el上
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
}
/**
* 初始化内部组件
*
* @param vm
* @param options
*/
export function initInternalComponent(
vm: Component,
options: InternalComponentOptions
) {
const opts = (vm.$options = Object.create((vm.constructor as any).options))
// doing this because it's faster than dynamic enumeration.
const parentVnode = options._parentVnode
opts.parent = options.parent
opts._parentVnode = parentVnode
const vnodeComponentOptions = parentVnode.componentOptions!
opts.propsData = vnodeComponentOptions.propsData
opts._parentListeners = vnodeComponentOptions.listeners
opts._renderChildren = vnodeComponentOptions.children
opts._componentTag = vnodeComponentOptions.tag
if (options.render) {
opts.render = options.render
opts.staticRenderFns = options.staticRenderFns
}
}
/**
* 解析构造函数的选项
*
* @param Ctor
* @returns
*/
export function resolveConstructorOptions(Ctor: typeof Component) {
let options = Ctor.options
if (Ctor.super) {
const superOptions = resolveConstructorOptions(Ctor.super)
const cachedSuperOptions = Ctor.superOptions
if (superOptions !== cachedSuperOptions) {
// super option changed,
// need to resolve new options.
Ctor.superOptions = superOptions
// check if there are any late-modified/attached options (#4976)
const modifiedOptions = resolveModifiedOptions(Ctor)
// update base extend options
if (modifiedOptions) {
extend(Ctor.extendOptions, modifiedOptions)
}
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
if (options.name) {
options.components[options.name] = Ctor
}
}
}
return options
}
/**
* 解析修改的选项
*
* @param Ctor
* @returns
*/
function resolveModifiedOptions(
Ctor: typeof Component
): Record<string, any> | null {
let modified
const latest = Ctor.options
const sealed = Ctor.sealedOptions
for (const key in latest) {
if (latest[key] !== sealed[key]) {
if (!modified) modified = {}
modified[key] = latest[key]
}
}
return modified
}
demo 位于
example/docs/01.lifecycle.html
通过debugger的方式,能够更直观的查看到整个调用的过程;这里罗列了选项式 api 和组合式 api,后续的 demo 都会以组合式 api 为主。
具体的 debugger 方法可以查看微软的文档devtools-guide-chromium,一般来说 F9 进行调试即可;如果你想跳过某一函数,那就 F10;
<script src="../../dist/vue.js"></script>
<div id="app">{{msg}}</div>
<script>
debugger
// Options API || 设置了el
// var app = new Vue({
// el: '#app',
// data: {
// msg: 'Hello Vue!'
// },
// beforeCreate() {
// console.log('beforeCreate')
// },
// created() {
// console.log('created')
// },
// beforeMount() {
// console.log('beforeMount')
// },
// mounted() {
// console.log('mounted')
// }
// })
// Options API || 手动$mount
// new Vue({
// data: () => ({
// msg: 'helloWord'
// }),
// beforeCreate: () => {
// console.log('beforeCreate')
// },
// created: () => {
// console.log('created')
// },
// beforeMount: () => {
// console.log('beforeMount')
// },
// mounted: () => {
// console.log('mounted')
// }
// }).$mount('#app')
// Composition API
const { ref, beforeCreate, created, beforeMount, mounted } = Vue
new Vue({
setup(props) {
const msg = ref('Hello World!')
return { msg }
},
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted')
}
}).$mount('#app')
</script>
这里我们总结下
init.ts中大致的内容
beforeCreate生命周期钩子函数created生命周期钩子函数,完成初始化el则自动挂载到对应的元素上,不然就要自己$mount;在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到rubygems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc
我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我正在写一篇关于在Ruby中几乎一切都是对象的博客文章,我试图通过以下示例来展示这一点:classCoolBeansattr_accessor:beansdefinitialize@bean=[]enddefcount_beans@beans.countendend所以从类中我们可以看出它有4个方法(当然,除非我错了):它可以在创建新实例时初始化一个默认的空bean数组它可以计算它有多少个bean它可以读取它有多少个bean(通过attr_accessor)它可以向空数组写入(或添加)更多bean(也通过attr_accessor)但是,当我询问类本身它有哪些实例方法时,我没有看到默认
我去了这个website查看Rails5.0.0和Rails5.1.1之间的区别为什么5.1.1不再包含:config/initializers/session_store.rb?谢谢 最佳答案 这是删除它的提交:Setupdefaultsessionstoreinternally,nolongerthroughanapplicationinitializer总而言之,新应用没有该初始化器,session存储默认设置为cookie存储。即与在该初始值设定项的生成版本中指定的值相同。 关于
我有一个类unzipper.rb,它使用Rubyzip解压文件。在我的本地环境中,我可以成功解压缩文件,而无需使用require'zip'明确包含依赖项但是在Heroku上,我得到一个NameError(uninitializedconstantUnzipper::Zip)我只能通过使用明确的require来解决问题:为什么这在Heroku环境中是必需的,但在本地主机上却不是?我的印象是Rails自动需要所有gem。app/services/unzipper.rbrequire'zip'#OnlyrequiredforHeroku.Workslocallywithout!class
我将gem推送到rubygems.org,当我执行“geminstall(gem)”时出现此错误:ERROR:Whileexecutinggem...(NameError)uninitializedconstantPsych::Syck我可以执行“gembuild(gem).gemspec”来生成本地gem,然后geminstall(gem).gem并且安装正常。我还可以将gem放入我的Rails应用程序的Gemfile中,并带有指向Github存储库的指针,这也可以。我试过在多台计算机上安装gem(来自rubygems.org,它们都遇到相同的错误。我不知道是什么原因导致从r
我写了很多initialize代码,将attrs设置为参数,类似于:classSiteClientattr_reader:login,:password,:domaindefinitialize(login,password,domain='somedefaultsite.com')@login=login@password=password@domain=domainendend有没有更像Ruby的方式来做到这一点?我觉得我在一遍又一遍地编写相同的样板设置代码。 最佳答案 您可以使用rubyStruct:classMyClass或