Skip to content
TOC

从一个 vue 文件,到渲染出界面,经历了哪些重要的步骤?

从一个 Vue 文件到渲染出界面的过程可以分为多个关键步骤。每个步骤都有具体的实现机制。以下是详细的步骤解析:

1. 编译阶段

a. 解析模板 (Template Parsing)

  • 解析 Vue 文件:一个 .vue 文件包含模板、脚本和样式部分。Vue 编译器首先将这个文件解析成各个部分。
  • 解析模板字符串:使用模板解析器 (parse 函数),将模板字符串解析成抽象语法树 (AST)。
html
<!-- Example Vue File -->
<template>
  <div id="app">
    <p>{{ message }}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        message: 'Hello, Vue!',
      };
    },
  };
</script>

b. 优化 AST (Optimize AST)

  • 静态节点标记:优化过程会遍历 AST,标记静态节点和静态子树。这样可以在更新过程中跳过这些静态内容,提高渲染性能。
javascript
// Example AST Node
{
  type: 1, // Element type
  tag: 'div',
  attrsList: [{ name: 'id', value: 'app' }],
  attrsMap: { id: 'app' },
  children: [
    {
      type: 1,
      tag: 'p',
      children: [
        {
          type: 2, // Expression type
          expression: '_s(message)',
          text: '{{ message }}'
        }
      ]
    }
  ]
}

c. 生成代码 (Code Generation)

  • 生成渲染函数代码:将优化后的 AST 转换成渲染函数代码字符串 (generate 函数)。这个过程会遍历 AST 并生成相应的代码。
javascript
// Generated Render Function Code
function render() {
  with (this) {
    return _c('div', { attrs: { id: 'app' } }, [_c('p', [_v(_s(message))])]);
  }
}

2. 运行时阶段

a. 初始化组件 (Component Initialization)

  • 创建组件实例:使用组件构造函数 (Vue.extend) 创建组件实例。
  • 初始化数据:在组件实例化过程中,Vue 会初始化数据 (data),将数据转化为响应式对象。
javascript
// Component Initialization
const vm = new Vue({
  data() {
    return {
      message: 'Hello, Vue!',
    };
  },
  render,
});

b. 渲染函数执行 (Render Function Execution)

  • 生成虚拟 DOM (VNode):调用渲染函数生成虚拟 DOM 树。
  • 创建渲染 Watcher:创建一个渲染 Watcher,用于追踪渲染函数中响应式数据的依赖。
javascript
// Render Function Execution
vm._render = function () {
  return this.$options.render.call(this);
};

c. 虚拟 DOM 映射到真实 DOM (VNode to DOM Mapping)

  • 创建真实 DOM:将虚拟 DOM 树转换成真实 DOM 元素,并插入到页面中。
  • 调用 patch 函数patch 函数用于比较虚拟 DOM 树的变化,并进行相应的 DOM 更新。
javascript
// Patch Function Example
function patch(oldVNode, vnode) {
  // Create real DOM elements from VNode
  const el = createElm(vnode);
  // Replace old DOM elements with new ones
  oldVNode.elm.parentNode.replaceChild(el, oldVNode.elm);
}

3. 更新阶段

a. 响应式系统 (Reactivity System)

  • 依赖收集:在渲染过程中,当访问响应式数据时,会触发 getter,记录依赖 (Watcher)。
  • 数据更新:当响应式数据发生变化时,触发 setter,通知依赖更新。
javascript
// Reactive Data Example
const data = {
  message: 'Hello, Vue!',
};
Object.defineProperty(data, 'message', {
  get() {
    // Collect dependency
  },
  set(newVal) {
    // Notify watchers
  },
});

b. 组件重新渲染 (Component Re-rendering)

  • 重新计算虚拟 DOM:当数据变化时,渲染 Watcher 会重新执行渲染函数,生成新的虚拟 DOM 树。
  • 比较新旧虚拟 DOMpatch 函数比较新旧虚拟 DOM 树的差异,进行最小化的 DOM 更新。
javascript
// Update Example
vm.message = 'Hello, World!';
// Re-render and patch the DOM
vm._update(vm._render());

总结

从一个 Vue 文件到渲染出界面的全过程如下:

  1. 编译阶段

    • 解析模板为 AST。
    • 优化 AST,标记静态节点。
    • 生成渲染函数代码。
  2. 运行时阶段

    • 初始化组件实例,创建响应式数据。
    • 执行渲染函数,生成虚拟 DOM 树。
    • 虚拟 DOM 树映射到真实 DOM,并插入页面。
  3. 更新阶段

    • 响应式系统追踪数据依赖和变化。
    • 数据更新时,重新计算虚拟 DOM 树。
    • 比较新旧虚拟 DOM 树,进行最小化 DOM 更新。

通过这些步骤,Vue 实现了高效的模板编译和数据驱动的视图更新。

Released under the CC BY-NC-ND 3.0