解析 Vue 模板的本质:从语法糖到渲染过程

news2024/10/21 18:27:23

大家耳熟能详的表述如下:Vue 模板的本质其实是一种 声明式渲染 的形式,它在开发过程中提供了将组件的结构与逻辑分离的便利。

也就是说,模板 template 的存在只是为了让我们以更直观的方式描述界面的结构,然而在运行时,模板其实是不存在的,它在底层会被 Vue 编译为更高效的 渲染函数

1. Vue 模版的本质

Vue 模板语法是基于 HTML 的拓展,它背后的运行机制是将模板编译为 JavaScript 的渲染函数。渲染函数生成 Virtual DOM(虚拟 DOM),并与真实 DOM 进行对比更新(diffing),进而提高渲染的性能。

渲染函数 render 本质上是一个 JavaScript 函数,用于描述 UI 如何与数据关联。Vue 的模板系统和 JSX、React 类似,但 Vue 的模板更加直观,不需要直接编写 JavaScript 函数。

那么 render 函数的作用是什么呢?它的主要任务是描述界面的渲染过程。通过 render 函数,Vue 可以生成虚拟节点,这些虚拟节点是对页面结构的抽象描述。也就是说,render 函数并不直接操作真实的 DOM,它返回的是一个虚拟 DOM,用于描述页面中包含的元素和内容。

在 Vue 中,常用的 h 函数(即 “createElement” 函数)负责创建这些虚拟节点,即 Vue 的虚拟节点就是在渲染函数中产生的。h 函数会根据传入的参数返回一个虚拟节点对象,而这个虚拟节点就是对页面结构的抽象表示。

编译过程:

1、模版编译:Vue 在运行时会将模板编译为渲染函数。这些渲染函数会生成虚拟 DOM。

2、虚拟 DOM 更新:当组件的状态或数据发生变化时,Vue 会重新调用渲染函数生成新的虚拟 DOM。

3、Diff 算法对比:Vue 将新生成的虚拟 DOM 与上一次生成的虚拟 DOM 进行比较,找出变化的地方。

4、真实 DOM 更新:最后,Vue 将变化更新到实际的 DOM 上。

2. Vue 模版的基本语法

1、插值表达式

插值表达式用于动态显示数据,常用 {{ }} 包裹 JavaScript 表达式:

🌰

<template>
  <p>{{ message }}</p>j
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, Vue!'
    }
  }
}
</script>

本质:{{ message }} 会被 Vue 编译为:

return _c('p', [_v(_s(message))])

其中 _s  是将数据转换为字符串,_v 是创建文本节点,_c 是创建元素节点。

2、指令(Directives)

Vue 的指令提供了一些特殊的 HTML 属性,以实现动态绑定。

🌰

<template>
  <div v-if="isVisible">Visible Content</div>
</template>

<script>
export default {
  data() {
    return {
      isVisible: true
    }
  }
}
</script>

本质:v-if  是一个条件渲染语法糖,编译后的代码可能是:

return isVisible ? _c('div', [_v('Visible Content')]) : _e()

其中:_e 是创建空的占位元素。 

3、事件处理

Vue 模板中可以使用 v-on 指令来绑定事件:

🌰

<template>
  <button @click="handleClick">Click me</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      console.log('Button clicked!')
    }
  }
}
</script>

本质:@click 是 v-on:click 的简写,编译后的代码类似:

return _c('button', {
  on: {
    click: function($event) {
      return handleClick($event)
    }
  }
}, [_v('Click me')])
4、列表渲染

Vue 使用 v-for 来遍历列表,并且支持对象和数组的迭代: 

🌰

<template>
  <ul>
    <li v-for="(item, index) in items" :key="index">{{ item }}</li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      items: ['Apple', 'Banana', 'Cherry']
    }
  }
}
</script>

本质:v-for 循环生成多个相同结构的节点,渲染函数可能是:

return _c('ul', items.map((item, index) => {
  return _c('li', { key: index }, [_v(_s(item))])
}))

 3. 使用渲染函数 h

除了模板,Vue 也允许开发者直接使用渲染函数来定义组件。

举个 🌰

在页面创建一个 ul 元素,ul 内部包含 100 个 li 元素,使用 render 的写法为:

import { h } from 'vue'
export default {
  setup() {
    return () => {
      const lis = []
      for (let i = 0; i < 100; i++) {
        const li = h('li', { class: 'item', key: i }, i)
        lis.push(li)
      }
      const ul = h('ul', { class: 'list' }, lis)
      return ul
    }
  }
}

页面结构展示: 

上述代码没有任何问题,只是书写起来比较复杂,因此 Vue 给我们提供一个语法糖 Template。

<template>
  <ul class="list">
    <li class="item" v-for="i in 100" :key="i">{{ i }}</li>
  </ul>
</template>

由此进一步引出一个问题:存在某一个东西,在某一个时间点,将上面的 template 模版转换为下面 render 函数。

到底是什么东西在什么时间点呢?

解释:

第一个问题:谁在做?

这个过程称为编译。编译是将一种代码转换成另一种代码的过程。

在 Vue.js 中,存在一个编译模块,将模板(template)转换成 JavaScript 的渲染函数(render function)。这个渲染函数是 Vue 实例化过程中用来生成虚拟 DOM 的核心。

编译器的角色

Vue.js 中的编译器负责将模板语法(如指令、插值等)转换成 JavaScript 代码。这个过程涉及到解析模板、优化和代码生成三个主要步骤:

1、解析模板:编译器首先解析模板中的指令和特殊语法,如 v-if、v-for、{{ expression }} 等。

2、优化:编译器会对解析结果进行优化,比如识别静态节点和避免不必要的 DOM 更新。

3、代码生成:最后,编译器将优化后的抽象语法树(AST)转换成可执行的 JavaScript 代码,即渲染函数。

第二个问题:什么时候编译?

编译时机是指编译过程发生的时间点,这直接影响到应用的性能和打包体积。分为以下两个:

1、运行时编译

在 Vue.js 的早期版本中,编译过程是在浏览器端运行时进行的。这意味着当用户访问应用时,浏览器需要下载 Vue.js 框架,然后动态地将模板编译成渲染函数。这种方式的缺点是:

1)性能开销:运行时编译会增加页面加载和渲染的时间,因为浏览器需要在运行时执行编译任务。

2)打包体积:由于需要包含模板编译模块,应用的打包体积会相对较大。

2、编译时编译

为了解决运行时编译带来的问题,Vue.js 引入了预编译的概念。在这个阶段,编译过程被移到了构建阶段,通常是在开发者执行 npm run build 命令时自动进行的。这种方式的优点是:

1)性能提升:由于编译过程在构建时已经完成,运行时浏览器只需要执行渲染函数,大大减少了页面加载和渲染的时间。

2)打包体积减小:因为模板编译模块只在构建时需要,所以最终的打包结果中不需要包含这部分代码,从而减少了应用的体积。

这也就解释了为什么工程化好的原因啦! 

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

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

相关文章

Android Framework AMS(09)service组件分析-3(bindService和unbindService关键流程分析)

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;上上一章节主要解读应用层service组件启动的2种方式startService和bindService&#xff0c;以及从APP层到AMS调用之间的打通。上一章节我们关注了s…

北京大学冯惠:与卓越者同行,方能更快的成长 | OceanBase数据库大赛获奖选手访谈

本文邀请2022 OceanBase 数据库大赛的季军&#xff0c;来自北京大学的冯惠同学&#xff0c;与我们分享如何寻找自己的兴趣&#xff1b;在一番经历后&#xff0c;对于产品与研发的职业方向观察&#xff1b;以及如何在学生时期提升个人专业能力&#xff0c;和参加数据库大赛的个人…

【Python技术】利用akshare定时获取股票实时价,低于5日线钉钉通知报警

今天看了下大盘&#xff0c;临时有个想法&#xff0c;我想知道某个股票回踩5日线的价格&#xff0c;如果实时价格低于5日线通过钉钉报警通知我。 说干就干&#xff0c;临时撸了下简单的代码&#xff0c;仅做演示。 1、计算5日线思路 很多券商软件的MA5价格是近5个交易日收盘…

Java项目-基于springboot框架的医患档案管理系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Hi3061M——VL53L0X激光测距(IIC)(同样适用于其他MCU)2

目录 前言资源下载移植基本使用IO配置调用测量 总结 前言 昨晚太晚了&#xff0c;草草结束了上一篇&#xff0c;今天更新下半部分。 昨天已经讲了VL53L0X的使用流程&#xff0c;无非就是进行6步的效准初始化&#xff0c;然后配置下模式和时间&#xff0c;开始采样&#xff0c;…

LDAP 部署手册

Centos 1. 安装openldap软件 # 安装openldap yum -y install openldap compat-openldap openldap-clients openldap-servers openldap-servers-sql openldap-devel migrationtoolscp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG chown ldap:ldap…

Leetcode 跳跃游戏 二

核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 这段代码解决的是“跳跃游戏 II”&#xff08;Leetcode第45题&#xff09;&#xff0c;其核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 class Solution {public int jump(int[] nums) {//首先处理特殊情…

“智驭医疗·未来已来“:医疗保健知识中台的搭建与应用

前言 随着科技的飞速发展&#xff0c;医疗保健领域正在经历深刻的变革。知识中台作为促进医疗行业应用智能化升级的关键底座&#xff0c;正在逐渐成为提高医疗服务质量和效率的重要工具。本文将探讨医疗保健知识中台的内容构成、应用案例以及更新与维护机制。 一、医疗保健知识…

基于ASP.NET的小型超市商品管理系统

文章目录 前言项目介绍技术介绍功能介绍核心代码数据库参考 系统效果图 前言 示 文章底部名片&#xff0c;获取项目的完整演示视频&#xff0c;免费解答技术疑问 项目介绍 小型超市商品管理系统是一款针对小型超市日常运营需求设计的软件解决方案。该系统主要内容有商品类别…

【JS】无法阻止屏幕滚动

监听滚轮事件&#xff0c;阻止默认行为&#xff0c;但未生效&#xff0c;且控制台报错。 window.addEventListener(wheel, (e) > {e.preventDefault(); })这是因为现代浏览器使用 Passive 事件监听器&#xff0c;默认启用了 passive 模式以确保性能&#xff0c;不会调用 pr…

【软件安装与配置】Redis for Windows

1. 下载 Redis Redis 官方没有直接支持 Windows 的安装程序&#xff0c;但可以使用第三方的 Windows 版本。推荐使用 Memurai 或从 Microsoft archive 提供的 Redis for Windows 下载。 2. 安装 Redis 下载适合 Windows 的安装包&#xff0c;本文以Microsoft archive安装包为…

Git_IDEA集成Git

Git_IDEA集成Git 配置 Git 忽略文件 创建忽略规则文件 引用忽略配置文件 定位 Git 程序 初始化本地库 添加到暂存区 提交到本地库 切换版本 创建分支 切换分支 合并分支 解决冲突 配置 Git 忽略文件 创建忽略规则文件 引用忽略配置文件 在 .gitconfig 文件中进行&…

[Git]一文速通

概述 Git是一个分布式版本控制工具&#xff0c;主要用于管理开发过程中的源代码文件(Java类、xml文件、html页面等, )在软件开发过程中被广泛使用 Git的作用 代码回溯版本切换多人协作远程备份 通过Git 仓库来存储和管理代码 文件&#xff0c;Git 仓库分为两种: 本地仓库: 开…

C++和OpenGL实现3D游戏编程【连载15】——着色器初步

&#x1f525;C和OpenGL实现3D游戏编程【目录】 1、本节实现的内容 上一节我们介绍了通过VBO、VAO和EBO怎样将顶点发送到GPU显存&#xff0c;利用GPU与显存之间的高效处理速度&#xff0c;来提高我们的图形渲染效率。那么在此过程中&#xff0c;我们又可以通过着色器&#xff…

webstorm 编辑器配置及配置迁移

1.下载地址 WebStorm&#xff1a;JetBrains 出品的 JavaScript 和 TypeScript IDE 其他版本下载地址 2.安装 点击下一步安装&#xff0c;可根据需要是否删除已有版本 注意&#xff1a; 完成安装后需要激活 3.设置快捷键 以下为个人常用可跳过或根据需要设置 如&#xff1a…

字幕怎么自动生成?教你5种视频加字幕方法

在这个短视频时代&#xff0c;视频内容已成为传播信息、娱乐大众的重要载体。而字幕作为视频不可或缺的一部分&#xff0c;不仅能够提升观众的观看体验&#xff0c;还能跨越语言障碍&#xff0c;让所有观众都能享受视频的魅力。但怎么给视频加上字幕呢&#xff1f;下面给大家分…

vulnhub靶场之JOY

一.环境搭建 1.靶场描述 Does penetration testing spark joy? If it does, this machine is for you. This machine is full of services, full of fun, but how many ways are there to align the stars? Perhaps, just like the child in all of us, we may find joy in …

Java最全面试题->Java基础面试题->JavaSE面试题->异常面试题

异常 下边是我自己整理的面试题&#xff0c;基本已经很全面了&#xff0c;想要的可以私信我&#xff0c;我会不定期去更新思维导图 哪里不会点哪里 1.说一下Java中的异常体系&#xff1f; 2.Error和Exception的区别 Error&#xff1a;系统错误,编译时出现的错误,Exception&…

宝兰德加入华为鸿蒙生态,共谱智能运维新篇章

近日&#xff0c;华为HarmonyOS NEXT系统&#xff08;又称“纯血鸿蒙”&#xff09;正式开启公测&#xff0c;标志着国产操作系统的发展迈入了新的阶段。作为华为紧密的战略合作伙伴&#xff0c;宝兰德依托其在IT监控运维可观测性领域的技术优势&#xff0c;正式成为华为鸿蒙Ha…

RFC2616 超文本传输协议 HTTP/1.1

一、URL-俗称“网址” HTTP 使用 URL(Uniform Resource Locator&#xff0c;统一资源定位符)来定位资源&#xff0c;它是 URI(Uniform Resource Identifier&#xff0c;统一资源标识符)的子集&#xff0c;URL 在 URI 的基础上增加了定位能力 URI 除了包含 URL&#xff0c;还包…