Vue源码学习笔记——组件挂载及创建

准备工作

备注:案例中使用的vue版本全部为2.6.10

git clone https://github.com/vuejs/vue.git
npm install

进入package.json,在script中增加"dev:read"命令,具体如下

  "scripts": {
     
  	// 方便源码阅读
    "dev:read": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web-full-dev",
    "dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
    ...
 }

在根目录下创建index.html文件,

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible"
        content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <h1>Hello {
     {
     name}}</h1>
  </div>

  <script src="./dist/vue.js"></script>

  <script>
    let vm = new Vue({
     
      data() {
     
        return {
     
          name: "Connie!"
        }
      },
    })

    vm.$mount('#app')
  </script>
</body>

</html>

动态监控生成vue.js 文件

npm run dev:read

打开index.html,可以在浏览器中看到vue的源码,并且可以修改源码内容,设置断点调试。

组件挂载$mount

查看入口文件package.json的dev:read命令
  //  其中入口文件为scripts/config.js, 命令为web-full-dev
  "dev:read": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web-full-dev",
config.js
 // 入口为web/entry-runtime-with-compiler.js,生成文件dist/vue.js,环境为development
 // Runtime+compiler development build (Browser)
 'web-full-dev': {
     
   entry: resolve('web/entry-runtime-with-compiler.js'),
   dest: resolve('dist/vue.js'),
   format: 'umd',
   env: 'development',
   alias: {
      he: './entity-decoder' },
   banner
 },
entry-runtime-with-compiler.js

文件路径: vue/src/platforms/web/entry-runtime-with-compiler.js
Vue源码学习笔记——组件挂载及创建_第1张图片
可以在此文件中终于找到我们想要的$mount函数,此函数返回的是一个vm组件,index.html 这样调用了

vm.$mount('#app')

现在继续往下看,我们来看这个函数中的几句核心代码

  // 1 获取element元素
  el = el && query(el)
  // 2 生成template,此处通过如下代码获取template
  template = getOuterHTML(el)
  // 3 通过compileToFunctions生成render函数,此案例中render函数长这样:)
  /**
    function anonymous(
    ) {
      with (this) {
        return _c(
          'div',
          { attrs: { "id": "app" } },
          [_c(
            'h1',
            [_v("Hello " + _s(name))]
          )]
        )
      }
    }
  */
  
  // 4 将render函数保存到vm.$options.render,以便在后续代码中使用
  options.render = render
  // 5 调用vue本身的mout函数,返回一个Component
  return mount.call(this, el, hydrating)
函数 mount.call(this, el, hydrating)

文件路径:vue/src/platforms/web/runtime/index.js

// 1 获取element 元素
el = el && inBrowser ? query(el) : undefined

// 2 挂载组件
mountComponent(this, el, hydrating)
mountComponent(this, el, hydrating)

文件路径:vue/src/core/instance/lifecycle.js

// 1.	保存Element
vm.$el = el

// 2.	调用beforeMount生命周期函数
  callHook(vm, 'beforeMount')

// 3.	设置updateComponent函数
/********重点核心代码********/
    updateComponent = () => {
     
    // vm._render()返回虚拟DOM VNode,下面会重点分析_render函数
      vm._update(vm._render(), hydrating)
    }

// 4.	设置观察者(vue1和vue2的重要区别)
  new Watcher(vm, updateComponent, noop, {
     
    before () {
     
      if (vm._isMounted && !vm._isDestroyed) {
     
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)

// 5.	调用mounted生命周期函数
  if (vm.$vnode == null) {
     
    vm._isMounted = true
    callHook(vm, 'mounted')
  }

// 6.	返回vm组件实例
  return vm
Vue.prototype._render

文件路径:vue/src/core/instance/render.js

/*******重点核心代码*********/
// 调用render函数生成虚拟DOM
// vm._renderProxy是vm本身,
// vm.$createElement 是h参数,用来新建虚拟dom
/* render是new Vue中的render函数
 new Vue({
      render: h=>h(APP)
 })
*/
// 组件的本质,div元素的本质,其实就是虚拟DOM
vnode = render.call(vm._renderProxy, vm.$createElement)
vm.$createElement 其实是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)

文件路径:vue/src/core/vdom/create-element.js

// 参数校验及调整
  if (Array.isArray(data) || isPrimitive(data)) {
     
    normalizationType = children
    children = data
    data = undefined
  }
  if (isTrue(alwaysNormalize)) {
     
    normalizationType = ALWAYS_NORMALIZE
  }
// 调用真正新建组件函数
_createElement(context, tag, data, children, normalizationType)

后续有待更新,争取每天更新一小部分:)…

你可能感兴趣的:(vue源码学习笔记,vue源码,vue)