vue源码解析

先注重源码入口,再关注功能细节

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
7. vue生命周期 https://segmentfault.com/a/1190000014640577?utm_source=tag-newest
8.计算属性本质是一个computed,watcher,会基于依赖进行缓存,data内的值发生变化,computed不一定会变化,当重新计算的值发生变化,才会去update 重新渲染,
9.监听属性本质是一个user watcher,他还支持deep,sync,immediate 等配置

你可能感兴趣的:(vue源码解析)