Vue.js设计与实现阅读-3

news2024/9/21 19:02:31

Vue设计与实现阅读-3

    • 1、声明式描述UI
    • 2、渲染器
    • 3、组件
    • 4、模板的工作原理
    • 5、Vue.js 是各个模块组成的有机整体

前言
前面一章我们了解了,开发体验是衡量一个框架的重要指标之一。提供友好的警告信息至关重要,但是越详细的警告信息,意味着框架体积越大。为了解决这一问题,可以利用 Tree-Shaking 机制,配合构建工具预定义常量,例如 __DEV __ ,从而实现只在开发环境中打印警告信息,生产环境中清楚这些代码,达到代码体积的可控性。
Tree-Shaking 是一种清除 dead code 的机制。可以利用/* #PURE */ 来辅助构建工具进行 Tree-Shaking。
框架的错误处理做的好坏决定了用户程序的健壮性,因此需要为用户提供统一的错误处理接口,这样用户可以通过注册自定义的错误处理函数来处理异常。

1、声明式描述UI

Vue.js 模板描述

<h1 @click="handleClick">
	<span></span>
</h1>

js 对象描述上面的UI

const title = {
	tag: 'h1',
	props: {
		onClick: handleClick
	},
	children: [
		{
			tag: 'span'
		}
	]
}

如果我们想表示一个标题,根据标题级别的不同,分别采用h1~ h6 这几个标签,如果用js实现

let level = 1;
const title = {
	tag: `h${level}`
}

如果 level 的值变化,相应的标签名称也会变化。但是如果用 模板来描述,就需要一个个列举出来。

<h1 v-if="level === 1"></h1>
<h2 v-else-if="level === 2"></h2>
...
<h6 v-else-if="level === 6"></h6>

远远没有js对象灵活。使用js对象来描述 UI 的方式,其实就是虚拟DOM。Vue3中除了支持使用模板描述 UI外,还支持虚拟DOM描述 UI。例如我们手写的渲染函数就是使用虚拟 DOM 描述UI。

import {h} from 'vue';
export default {
	render() {
		return h('h1', {
			onClick: handleClick
		})
	}
}

2、渲染器

虚拟 DOM 就是用 JS 对象来描述真实的DOM结构。如何将虚拟DOM变成真实的DOM并且渲染到浏览器页面中---渲染器

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

虚拟DOM如下:

const vnode = {
	tag: 'div',
	props: {
		onClick: () => alert('hello')
	},
	children: 'click me'
}

编写一个 渲染器,将上面的虚拟 DOM 渲染成真实DOM

function renderer (vnode, container) {
	// 创建 dom 元素
	const el = document.createElement(vnode.tag);
	// 添加属性、事件到 dom 元素
	for (const key in vnode.props) {
		if (/^on/.test(key)) {
			// on 开头,事件,给元素绑定事件
			el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
		}
	}
	// children 处理
	if (typeof vnode.children === 'string') {
		// string -- 文本
		el.appendChild(document.createTextNode(vnode.children));
	} else if (Array.isArray(vnode.children)) {
		// 数组,递归调用,渲染子节点
		vnode.children.forEach(child => renderer(child, el));
	}
	container.appendChild(el)
}

运行结果:
在这里插入图片描述
上述分析器实现思路

  • 创建DOM元素,vnode.tag 为标签名
  • 给元素添加属性和事件。遍历 props 对象,如果 key 是 on 开头,说明是事件,截取字符 on 使用 toLowerCase将事件名称小写,再调用 addEventListener 绑定事件
  • 处理元素的 children。如果是字符串,创建文本节点,如果是数组,递归调用 renderer 函数渲染。

发现渲染器实现起来也很简单,主要是使用一些熟悉的 DOM 操作 API 来完成渲染工作。上面只是创建节点,渲染器的精髓在更新节点的阶段,需要精确找啊到 vnode对象的变更点,并且只更新变更的内容。

3、组件

上面了解了渲染器会将虚拟 DOM 渲染成真实的 DOM 元素。那组件呢,组件和虚拟 DOM 之前有什么关系。

**组件是一组 DOM 元素的封装,这组 DOM 元素就是组件要渲染的内容。**定义一个函数来代表组件,函数的返回值代表组件要渲染的内容。

const MyComponent = function () {
    return {
        tag: 'div',
        props: {
            onClick: () => alert('click')
        },
        children: 'click me'
    }
}

可以看到组件的 返回值也是虚拟 DOM,代表了组件要渲染的内容,那么我们就可以使用下面的方式来描述组件。其中 tag 可以用来描述组件。

const vnode = {
	tag: MyComponent
}

修改之前的渲染函数

	// 渲染函数
    renderer(vnode, container) {
        if (typeof vnode.tag === 'string') {
            // string -- 普通标签元素
            this.mountElement(vnode, container);
        } else if (typeof vnode.tag === 'function') {
            // string -- 组件
            this.mountComponent(vnode, container);
        }
    },
    
    // 渲染标签元素
    mountElement(vnode, container) {
        // 创建 dom 元素
        const el = document.createElement(vnode.tag);
        // 添加属性、事件到 dom 元素
        for (const key in vnode.props) {
            if (/^on/.test(key)) {
                // on 开头,事件,给元素绑定事件
                el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
            }
        }
        // children 处理
        if (typeof vnode.children === 'string') {
            // string -- 文本
            el.appendChild(document.createTextNode(vnode.children));
        } else if (Array.isArray(vnode.children)) {
            // 数组,递归调用,渲染子节点
            vnode.children.forEach(child => this.renderer(child, el));
        }
        container.appendChild(el)
    },
    
     // 渲染组件
    mountComponent(vnode, container) {
        // 调用组件函数,获取要渲染的内容
        const subTree = vnode.tag();
        this.renderer(subTree, container)
    },

4、模板的工作原理

上面我们了解了虚拟 DOM 是如何渲染成真实 DOM的,那么模板是如何工作的呢?其实是依赖于编译器。

编译器的作用是将模板编译成渲染函数。
模板如下

<div @click="handleClick">click me</div>

对编译器来说,模板相当于一个字符串,它会分析字符串并生成一个功能与之相同的渲染函数:

render() {
	return h('div', {onClick: handleClick}, 'click me')
}

在 Vue中一个.vue文件就是一个组件

<template>
    <div @click="handleClick">
        click me
    </div>
</template>

<script>
export default {
    data() {
        return {
        }
    },
    methods: {
        handleClick() {
            // do nothing
        }
    }
}
</script>

其中 < template > 标签里的内容为模板内容,编译器会把模板内容编译成渲染函数并且添加到 script 标签上,最终在浏览器里面运行的代码就是

export default {
    data() {
        return {
        }
    },
    methods: {
        handleClick() {
            // do nothing
        }
    },
    render() {
		return h('div', {onClick: handleClick}, 'click me')
	}
}

对一个组件来说,他要渲染的内容最终都是通过渲染函数产生的,渲染器再将渲染函数返回的虚拟 DOM 渲染为真实 DOM,这就是模板的工作原理,也是 Vue.js 渲染页面的过程。

5、Vue.js 是各个模块组成的有机整体

组件的实现依赖于渲染器,模板的编译依赖于编译器。编译后生成的代码是根据渲染器和虚拟 DOM的设计决定的。 因此Vue的各个模块之间是相互关联,相互制约的。
模板

<div id="foo" :class="cls"></div>

渲染函数

render() {
	return {
		tag: 'div',
		props: {
			id: 'foo',
			class: 'cls'
		}
	}
}

cls 是一个动态属性,那编译器如何知道 cls 发生了变化呢。从上面的模板 我们可以看出 id 是不会发生变化的, :class 可能会发生变化。编译器能识别出哪些是静态属性,哪些是动态属性,因此可以在生成代码的时候,标志出哪些是动态的属性。

render() {
	return {
		tag: 'div',
		props: {
			id: 'foo',
			class: 'cls'
		},
		patchFlags: 1  // 1 代表 class是动态的
	}
}

在虚拟 DOM 中多了一个 patchFlags 属性标志 class 的类型是动态还是静态,这样渲染器可以根据这个标志,知道有什么属性会发生变化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1381539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端 TS 语法继承 多态 修饰符 readonly 抽象类 ts 基本写法 可选 剩余参数 函数重载 接口 类(3)

继承 继承之间的叫法 A类继承了B类&#xff0c;那么A类叫做子类&#xff0c;B类叫成基类 子类 ---》派生类 基类 ---》超类&#xff08;父类&#xff09; // 继承之间的叫法 // A类继承了B类&#xff0c;那么A类叫做子类&#xff0c;B类叫成基类 // 子类 ---》派生类 // 基类 …

性能瓶颈分析定位

用vmstat、sar、iostat检测是否是CPU瓶颈 用free、vmstat检测是否是内存瓶颈 用iostat、dmesg 检测是否是磁盘I/O瓶颈 用netstat检测是否是网络带宽瓶颈 1 首先进行OS层面的检查确认 首先要确认当前到底是哪些进程引起的负载高&#xff0c;以及这些进程卡在什么地方&#x…

sectigo ip证书种类买一年送一月

Sectigo旗下的IP证书是专为只有公网IP地址的网站准备的。Sectigo旗下的数字证书大多是域名证书&#xff0c;例如&#xff0c;单域名SSL证书、多域名SSL证书、通配符SSL证书等。这些证书申请时必须验证域名所有权&#xff0c;申请者需要有一个拥有管理全的域名网站&#xff0c;那…

SpringIOC之support模块GenericGroovyApplicationContext

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

RAG代码实操之斗气强者萧炎

&#x1f4d1;前言 本文主要是【RAG】——RAG代码实操的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&#x…

京东宣布启动鸿蒙原生应用开发,全力支持鸿蒙生态 | 百能云芯

华为常务董事、终端BG CEO、智能汽车解决方案BU董事长余承东于1月10日在微博上发布了一条令人振奋的消息&#xff1a;京东即将启动鸿蒙原生应用的开发。这一消息在科技圈掀起了不小的波澜&#xff0c;也为鸿蒙系统的发展注入了新的动力。 京东集团首席执行官兼执行董事许冉和余…

10年果粉拯救老掉牙Mac心得(没错我是标题党)

连续两周了&#xff0c;当我不能用Mac,或者说当我闲置了近10年隔三差五的用Mac时&#xff0c;成功发现我的AppleID已经无法登录了。事情是这样的&#xff0c;当我踌躇满志地准备改一篇稿子&#xff08;潜在的稿费啊亲&#xff01;&#xff09;时&#xff0c;发现Pages竟然没有W…

Android Studio导入项目 下载gradle很慢或连接超时

AS最常见的问题之一就是下载gradle非常慢&#xff0c;还经常出现下载失败的情况&#xff0c;没有gradle就无法build项目&#xff0c;所以一定要先解决gradle的下载问题&#xff0c;下面教大家两种常用方法。 因为我的项目绝大多数使用的是gradle-5.6.4-all&#xff0c;下面就以…

谷歌DeepMind最新成果:机器人灵巧操作服务我们日常生活

谷歌DeepMind最新成果&#xff1a;机器人灵巧操作服务我们日常生活 CAAI认知系统与信息处理专委会 2024-01-13 00:00 发表于北京 几乎是和斯坦福“炒虾洗碗”机器人同一时间&#xff0c;谷歌DeepMind也发布了最新具身智能成果。 并且是三连发&#xff1a; 先是一个主打提高决…

FPGA(基于xilinx)中PCIe介绍以及IP核XDMA的使用

Xilinx中PCIe简介以及IP核XDMA的使用 例如&#xff1a;第一章 PCIe简介以及IP核的使用 文章目录 Xilinx中PCIe简介以及IP核XDMA的使用一、PCIe总线概述1.PCIe 总线架构2.PCIe 不同版本的性能指标及带宽计算3.PCIe 接口信号 二、XDMA1.XDMA 与其它 PCIe IP 的区别2.XDMA简介 三…

用Kimi chat识别并整理图片里面的文字

Kimi chat是有OCR功能的&#xff0c;可以识别图片中的文字。 下面这张图片是一本书的注释&#xff0c;里面提到有不少图书&#xff0c;利用Kimi chat就可以轻松完成提取其中图书书名的任务。 先拿一张图片来做实验。Kimichat的回复&#xff1a; 在您提供的文件内容中&#xf…

【重学C语言】二、前期准备和第一个C程序

【重学C语言】二、前期准备和第一个C程序 1. VS 项目1.1 创建项目 2. Clion 项目(本博主主用)2.1 创建项目2.2 Clion 配置 3. 构建类型4. 构建模式5. 注释6. 第一个 C 程序7. 程序闪退8. 新手遇到的问题 1. VS 项目 1.1 创建项目 打开 VS 创建新项目 创建 main.c 书写以下…

如何提高比例阀控制精度效率速度解决电磁阀线圈老化提供电磁阀速度柱塞检测电磁阀过流保护电磁阀菊花链控制MAX22216

越来越多的场合需要对进气量液压量进行精确控制&#xff0c;比例阀被大量采用&#xff0c;如何提高比例阀的控制精度和效率&#xff0c;本文介绍螺线管驱动芯片MAX22216MAX22217的12位PI电流闭环控制以及其他性能&#xff0c;可以提升比例阀的控制精度。提高电磁阀速度精度解决…

oracle—IMU机制

正常的情况下&#xff0c;当事务需要回滚块的时候&#xff0c;是去undo表空间找 现在是在sharepool中分一个IMUbuffer&#xff0c;将所有的回滚信息写入。直接就可以从中取。减少了物理IO 同时这个过程也产生redo&#xff0c;直接就是图中红色的&#xff0c;不防止崩溃 优点 1…

竞赛保研 基于计算机视觉的身份证识别系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的身份证识别系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-sen…

U盘安装XP纯净版系统教程软件安装教程(附软件下载地址)

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; U盘安装XP纯净版系统是一种便捷且快速的方式&#xff0c;以实现系统重装或升级的需求。这篇教程将为您详细介绍如何使用U盘来安装XP纯净版系统。XP纯…

JVM基础(7)——ParNew垃圾回收器

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

stable-diffusion 学习笔记

从效果看Stable Diffusion中的采样方法 参考&#xff1a;Ai 绘图日常 篇二&#xff1a;从效果看Stable Diffusion中的采样方法_软件应用_什么值得买 大概示例&#xff1a;

从零开始的源码搭建:详解连锁餐饮行业中的点餐小程序开发

时下&#xff0c;点餐小程序成为了许多餐饮企业引入的一种创新工具&#xff0c;不仅方便了顾客的用餐体验&#xff0c;同时也提高了餐厅的运营效率。本文将详细探讨如何从零开始搭建一个源码&#xff0c;并深入解析连锁餐饮行业中的点餐小程序开发过程。 一、需求分析与规划 在…

数据结构——排序算法之快速排序

个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C/C小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 前言&#xff1a; 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法。 基本思想&…