Vue.js设计与实现(1-3)

框架设计概览#Vue.js 3的设计思路

框架设计讲究全局视角的把控,围绕核心思路展开。

一、Vue.js 3的设计思路:声明式地描述UI

Vue.js 是一个声明式的 UI 框架。

编写前端页面 声明式 UI 描述 举例说明
DOM 元素 使用与 HTML 标签一致的方式 div 标签还是 a 标签
属性 使用与 HTML 标签一致的方式 使用 :v-bind 来描述动态绑定的属性 a 标签的 href 属性,及通用属性 idclass
事件 使用 @v-on 来描述事件 clickkeydown
元素的层级结构 使用与 HTML 标签一致的方式 DOM 树的层级结构,既有子节点,又有父节点

声明式地描述 UI:用户不需要手写任何命令式代码。

  1. 使用模板 描述

    html 复制代码
    <h1 @click="handleClick">
      <span></span>
    </h1>
  2. 使用 JavaScript 对象 描述

    javascript 复制代码
    const title = {
      // 标签名称
      tag: 'h1',
      // 标签属性
      props: {
        onClick: handleClick,
      },
      // 子节点
      children: [
        {
          tag: 'span',
        },
      ],
    }

使用模板描述更直观,使用 JavaScript 对象描述更灵活。

例:h1 ~ h6 不同级别标题的表示

javascript 复制代码
/**
 * 模板描述:穷举
 */
<h1 v-if="level === 1"></h1>
<h2 v-if="level === 2"></h2>
<h3 v-if="level === 3"></h3>
<h4 v-if="level === 4"></h4>
<h5 v-if="level === 5"></h5>
<h6 v-if="level === 6"></h6>

/**
 * JavaScript对象描述:变量代表
 */
let level = 3 // h 标签的级别
const title = {
  tag: `h${level}`, // h3标签
}

使用 JavaScript 对象来描述 UI 的方式,就是所谓的虚拟 DOM

渲染函数render 函数,描述一个组件要渲染的内容。

Vue.js 根据组件的 render 函数的返回值拿到虚拟 DOM,然后就可以把组件的内容渲染出来了。

二、Vue.js 3的设计思路:初识渲染器

渲染器的作用就是把虚拟 DOM 渲染为真实 DOM

  1. 虚拟 DOM

    javascript 复制代码
    const vnode = {
      tag: 'div',
      props: {
        onClick: () => alert('hello')
      },
      children: 'click me'
    }
    • tag:标签名称。
    • props:一个对象,描述标签的属性、事件等内容。
    • children:可以是一个字符串,也可以是一个数组,描述标签的子节点信息。
  2. 渲染器

    javascript 复制代码
    const renderer = (vnode, container) => {
      // 步骤一:创建元素
      const el = document.createElement(vnode.tag)
      
      // 步骤二:为元素添加属性和事件
      for (const key in vnode.props) {
        if (/^on/.test(key)) {
          el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
        } else {
          // TODO: 属性解析-class, style, 其他动态属性...
        }
      }
      
      // 步骤三:处理 children
      if (typeof vnode.children === 'string') {
        // 字符串:文本节点
        el.appendChild(document.createTextNode(vnode.children))
      } else if (Array.isArray(vnode.children)) {
        // 数组:递归渲染
        vnode.children.forEach(child => renderer(child, el))
      }
    
      container.appendChild(el)
    }
    • vnode:虚拟 DOM 对象。
    • container:一个真实 DOM 元素,作为挂载点,渲染器会把虚拟 DOM 渲染到该挂载点下。
  3. 真实 DOM

    javascript 复制代码
    // 初始将 body 作为挂载点
    renderer(vnode, document.body)

渲染器的实现思路

  1. 创建元素
  2. 为元素添加属性和事件
  3. 处理 children

渲染器的工作原理

递归地遍历虚拟 DOM 对象,并调用原生 DOM API 来完成真实 DOM 的创建。

三、Vue.js 3的设计思路:组件的本质

虚拟 DOM 除了能够描述真实 DOM 之外,还能够描述组件。

组件就是一组 DOM 元素的封装 ,这组 DOM 元素就是组件要渲染的内容。

  1. 虚拟DOM

    javascript 复制代码
    const vnode = {
        tag: 'div',
        props: {
            onClick: () => alert('hello')
        },
        children: 'click me'
    }
    
    /**
     * 直接渲染
     */
    const mountComponent = (vnode, container) => {
        // typeof vnode.tag === 'string'        
        renderer(subtree, container)
    }
  2. 组件函数

    javascript 复制代码
    const MyComponent = function () {
        // 组件返回虚拟 DOM
        return {
            tag: 'div',
            props: {
                onClick: () => alert('hello')
            },
            children: 'click me'
        }
    }
    
    /**
     * 渲染组件
     */
    const mountComponent = (vnode, container) => {
        // typeof vnode.tag === 'function'
        const subtree = vnode.tag()
        
        renderer(subtree, container)
    }
  3. 组件对象

    javascript 复制代码
    const MyComponent = {
        // 组件的方法返回虚拟DOM
        render() {
            return {
                tag: 'div',
                props: {
                    onClick: () => alert('hello')
                },
                children: 'click me'
            }
        }
    }
    
    /**
     * 渲染组件
     */
    const mountComponent = (vnode, container) => {
        // typeof vnode.tag === 'object'
        const subtree = vnode.tag.render()
        
        renderer(subtree, container)
    }

不同形式的虚拟 DOM ,对应不同的渲染逻辑:渲染器渲染的内容始终是最纯粹的虚拟 DOM

四、Vue.js 3的设计思路:模板的工作原理

编译器:将模板编译为渲染函数。

  • 模板内容

    html 复制代码
    <div @click="handler">click me</div>
  • 渲染函数

    javascript 复制代码
    render() {
        return h('div', { onClick: handler }, 'click me')
    }

无论是使用模板还是直接手写渲染函数,对于一个组件来说,它要渲染的内容最终都是通过渲染函数产生的,然后渲染器再把渲染函数返回的虚拟 DOM 渲染为真实 DOM,这就是模板的工作原理,也是 Vue.js 渲染页面的流程。 ------ 渲染器把渲染函数产生的虚拟 DOM 渲染为真实 DOM

五、Vue.js 3的设计思路:Vue.js是各个模块组成的有机整体

  • 组件的实现依赖于渲染器
  • 模板的编译依赖于编译器
  • 编译后生成的代码是根据渲染器和虚拟 DOM 的设计决定的

编译器、渲染器都是 Vue.js 的核心组成部分,它们共同构成一个有机的整体,不同模块之间相互配合,进一步提升框架性能。

相关推荐
加班是不可能的,除非双倍日工资5 分钟前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi39 分钟前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip1 小时前
vite和webpack打包结构控制
前端·javascript
excel1 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国2 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼2 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy2 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
草梅友仁2 小时前
草梅 Auth 1.4.0 发布与 ESLint v9 更新 | 2025 年第 33 周草梅周报
vue.js·github·nuxt.js
ZXT2 小时前
promise & async await总结
前端
Jerry说前后端2 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化