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

相关推荐
咬人喵喵6 分钟前
CSS Flexbox:拥有魔法的排版盒子
前端·css
LYFlied7 分钟前
TS-Loader 源码解析与自定义 Webpack Loader 开发指南
前端·webpack·node.js·编译·打包
yzp01129 分钟前
css收集
前端·css
暴富的Tdy9 分钟前
【Webpack 的核心应用场景】
前端·webpack·node.js
遇见很ok9 分钟前
Web Worker
前端·javascript·vue.js
风舞红枫12 分钟前
前端可配置权限规则案例
前端
前端不太难14 分钟前
RN Navigation vs Vue Router:从架构底层到工程实践的深度对比
javascript·vue.js·架构
zhougl99622 分钟前
前端模块化
前端
暴富暴富暴富啦啦啦38 分钟前
Map 缓存和拿取
前端·javascript·缓存
天问一39 分钟前
前端Vue使用js-audio-plugin实现录音功能
前端·javascript·vue.js