起因
年初接手的学校的物理实验中心的系统也基本上完工了,现在在测试,准备上线阶段。
前后有7个人参加,有几个坚持了一两个月,一直坚持下来的有4个,写了大半年的代码,前端的11多行代码(git fame统计的提交情况)。从一个小白,现在已经emmm,还不能说大神,顶多就是随便一个页面都可以写出来吧,适配各种产品也ok。总之就是前端的基础都已经很熟了,后端也差不多。
然后很熟过后,考虑问题时自然就比最开始提升了一个层次,刚开始接手时,才刚刚能把vue界面看懂,写一些简单的页面,当时只想着做出来就行了,其他的先都不管,结果命名、文件位置、样式等都是乱的。
每次理解项目时都是凭着自己是管理整个项目的,对整理项目的结构很清楚,每个页面的文件在哪,每个功能涉及到哪些变量、函数以及其位置等都很清楚;但对于其他人就有点eeee,mmm。
然后就想着等这次上线后,在准备做第二版阶段,把整个系统的架构给整理清楚以及代码规范等都要制定清楚,这就放在以后再说。这系列文章的重点还是vue源码。
随着技术的提升, 随之一起的不只是对项目的架构的关注,还有思考的层次,以前没有想过性能;大一时也曾疯狂的刷过题,但当时就实在是不清楚理解这些算法有什么用?做学术研究?跟做数学题一样,很难提取兴趣,如果长时间没有成果,则很难再坚持下去。
然而,现在写代码的时候却时不时的往组织,效率和原理的方面考虑,怎样写使代码量最少、时间最快、以及整个流程其内部是怎么运行的。
然后再找资料的过程中,发现大部分都是与面试、源码有关的,并且自己也试着听了几节,结果很有用,解答了我很多积攒已久的困惑。然后现在的打算就是,把vue的源码和数据库性能优化学习完后就去面试。
先定个小目标,看能否在开学前学完,加油吧。
这里附上一句自己很喜欢的话:
每当你被漫天的乌云压的喘不过气时,往往是一切问题解决的时候。而当你感觉晴空万里时,其实并没你想得那样好。
入口
位置: src/platforms/web/entry-runtime-with-compiler.js
入口文件,覆盖$mount,执行模板解析和编译工作
//挂载方法,保存原来的$mount
const mount = Vue.prototype.$mount
//覆盖或扩展默认的$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
/* istanbul ignore if */
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== 'production' && warn(
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`
)
return this
}
//解析option选项
const options = this.$options
// resolve template/el and convert to render function
//先判断是否有render
if (!options.render) {
let template = options.template
// 模板解析
if (template) {
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
template = idToTemplate(template)
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
}
} else if (template.nodeType) {
template = template.innerHTML
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this)
}
return this
}
} else if (el) {
template = getOuterHTML(el)
}
// 如果存在模板,执行编译
if (template) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile')
}
//得到渲染函数
const { render, staticRenderFns } = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end')
measure(`vue ${this._name} compile`, 'compile', 'compile end')
}
}
}
// 执行挂载
return mount.call(this, el, hydrating)
}
src/core/index.js
定义全局API
//定义全局API
initGlobalAPI(Vue)
src\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)
}
initMixin(Vue) //通过该方法给vue添加_init方法
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
src/core/instance/init.js
初始化方法init定义的地方
定义实例方法
initMixin(Vue) //通过该方法给vue添加_init方法
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
initLifecycle(vm) // 声明 $parent, $root, $children, $refs
initEvents(vm) // 对父组件传入事件添加监听(@...)
initRender(vm) // 声明$slots, $createElement()
callHook(vm, 'beforeCreate') //调用beforeCreate的钩子
initInjections(vm) // 注入数据
initState(vm) // 重要:数据初始化,响应式
initProvide(vm) // 提供数据
callHook(vm, 'created')
初始化过程
new Vue() :调用init
=> this._init(options) 初始化各种属性
=> $mount 调用mountcomponent()
=> mountcomponent() 申明updateComponent,创建watcher
=> _render() 获取虚拟dom
=> _update() 把虚拟dom转换为真实dom