先注重源码入口,再关注功能细节
vue源码入口文件:
// vue-dev/package.json
"module": "dist/vue.runtime.esm.js",
//支持es6,源码看这里
// vue-dev/scripts/config.js
'web-full-esm': {
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.esm.js'),
format: 'es',
alias: { he: './entity-decoder' },
banner
},
// 定义vue的地方
// vue-dev/src/core/instance/index.js
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
// 终于找到vue定义的地方
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')
}
// 执行_init函数
this._init(options)
}
// 5个扩展方法
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
- vue这么多版本with-compile版本是干啥的
vue解析过程,先把template解析成render函数,render函数返回虚拟DOM,从tempalte转换成render这一步叫做compile,这一步可以在webpack搞得,实际线上运行时没有compile版本的
- 两个重要的方法patch, render. patch是diff的过程,render是渲染的一个方法生成VDOM, 传入的h函数实际就是vm.$createElement方法
Vue.prototype._render = function (): VNode {
const vm: Component = this
const { render, _parentVnode } = vm.$options
if (_parentVnode) {
vm.$scopedSlots = normalizeScopedSlots(
_parentVnode.data.scopedSlots,
vm.$slots,
vm.$scopedSlots
)
}
// set parent vnode. this allows render functions to have access
// to the data on the placeholder node.
vm.$vnode = _parentVnode
// render self
let vnode
try {
// There's no need to maintain a stack because all render fns are called
// separately from one another. Nested component's render fns are called
// when parent component is patched.
currentRenderingInstance = vm
// 重点方法
vnode = render.call(vm._renderProxy, vm.$createElement) `
} catch (e) {
handleError(e, vm, `render`)
// return error render result,
// or previous vnode to prevent render error causing blank component
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
try {
vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
} catch (e) {
handleError(e, vm, `renderError`)
vnode = vm._vnode
}
} else {
vnode = vm._vnode
}
} finally {
currentRenderingInstance = null
}
// if the returned array contains only a single node, allow it
if (Array.isArray(vnode) && vnode.length === 1) {
vnode = vnode[0]
}
// return empty vnode in case the render function errored out
if (!(vnode instanceof VNode)) {
if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
warn(
'Multiple root nodes returned from render function. Render function ' +
'should return a single root node.',
vm
)
}
vnode = createEmptyVNode()
}
// set parent
vnode.parent = _parentVnode
return vnode
}
1. vue响应式(数据绑定)原理:
vue利用了Object.defineProperty属性,将data内的数据都定义了一个get,set 属性,这样让我们有机会监听data内属性的变化,当这些数据变化的时候,可以通知那些需要更新的地方去做更新
2. vue双向绑定的原理(v-model = :model + @input):
将v-model所属的事件上面加上事件监听(addEventListener), 作为input事件的回调函数,如果input 的值发生变化,就会将其设置到vue的实例上,因为vue实例已经实现了响应化,实例中属性的setter方法会触发依赖的更新。
3. VUE编译过程是怎样的(思路:w w w h):
why: vue语法编写的模板HTML无法识别所以需要编译,通过编译的过程我们可以进行依赖收集(dep),依赖收集以后,可以将data内的数据模型跟视图之间产生了绑定依赖关系(每一个数据模型都会绑定一个watcher),如果以后模型发生变化后,(watcher)就会 通知视图依赖产生更新(update)
4. new vue()过程:初始化: 数据的响应化 (dataReactive),对data内的数据劫持,通过Object.defineProperty
编译: 依赖收集(dep),创建watcher,dep管理所以的watcher
5. 路由守卫可以处理全局登录问题
...router.beforeEach(to,from,next) =>{ if(to.meta.auth) { // 需要登录 const token = localStoreage.getItem('token') if(token){ next() }else{ next({ path: '', query: {redirect: to.path} }) } else{ // 不需要登录 next() }
...
6. [vue-router][1]完整的导航解析流程 :
导航被触发。
在失活的组件里调用离开守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。 https://router.vuejs.org/zh/guide/advanced/navigation-guards.html