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 的核心组成部分,它们共同构成一个有机的整体,不同模块之间相互配合,进一步提升框架性能。

相关推荐
尾善爱看海8 小时前
Vue 面试收官篇:SSR、性能优化落地、30 道高频面试题精讲(附标准答案)
前端·javascript·vue.js·面试·vue
weixin_BYSJ19878 小时前
【计算机毕设】基于SpringBoot与Vue的文物保护档案管理系统08621
vue.js·spring boot·spring cloud·微服务·架构·django·课程设计
Bs_MoneyMagnet8 小时前
基于springboot+vue的个人健康管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·vue3·springboot3·计算机毕业设计
驳是8 小时前
一个组件,提升 react-router 开发的幸福感
前端·preact
GreenTea8 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
星云API技术支持9 小时前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信
京东云开发者9 小时前
81.8 秒的视频,我们改了 15 个版本:一次纯 Codex 驱动的 AI-native 视频实践
前端·aigc
Csvn9 小时前
TypeScript 大型项目架构:从单体 tsconfig 到分层可扩展的工程
前端
Bs_MoneyMagnet11 小时前
基于springboot+vue的心理咨询预约与随访平台的设计与实现 源码+文档
vue.js·spring boot·后端·spring·毕业设计·旅游·计算机毕业设计
计算机魔术师11 小时前
Dario Amodei 发文呼吁为前沿 AI 降速并提出三点计划
前端