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

相关推荐
正小安21 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常2 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr3 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho4 小时前
【TypeScript】知识点梳理(三)
前端·typescript