【Vue原理解析】之模版编译

引言

Vue.js是一款流行的JavaScript框架,它采用了基于组件的开发模式,使得前端开发更加简单和高效。而Vue的核心功能之一就是模版解析,它负责将Vue组件中的模版代码转化为可执行的JavaScript代码。本文将深入探讨Vue模版解析的作用、核心源码分析以及总结。

模版解析的作用

在Vue中,我们可以使用类似HTML的语法编写组件的模版代码。这些模版代码包含了数据绑定、指令、事件等功能,但浏览器无法直接理解和执行这些代码。因此,Vue需要将这些模版代码进行解析,并生成可执行的JavaScript代码。

核心源码分析

在Vue中,模版解析是通过编译器实现的。编译器会将组件中的模版代码转化为一个渲染函数(render function),这个渲染函数可以接收数据作为参数,并返回一个虚拟DOM(Virtual DOM)树。

1. 词法分析和语法分析

在模版解析过程中,首先需要对模版进行词法分析和语法分析,将其转化为一个抽象语法树(AST)。Vue使用了一个名为parse的函数来完成这个过程。其主要的方法则是parseHtml

 
// src/compiler/parser/index.ts
export function parse(template, options) {// ...const stack = []let root, currentParent// ...parseHTML(template, {// ...start(tag, attrs, unary, start, end) {// ...let element = createASTElement(tag, attrs, currentParent)if (!root) {root = element}if (!unary) {currentParent = elementstack.push(element)} else {closeElement(element)}},// ...end(tag, start, end) {// ...stack.length -= 1currentParent = stack[stack.length - 1]},// ...})return root
}

在这段代码中,我们可以看到parse函数接收一个模版字符串和一些选项作为参数。它使用了一个栈来保存当前正在处理的元素节点,并通过调用createASTElement函数创建了一个抽象语法树节点,并将其添加到当前父节点的子节点列表中。

  1. parse函数:

    • parse函数是模版编译的入口函数,它接收一个模版字符串和一些选项作为参数。
    • parse函数内部创建了一个栈(stack)用于保存当前正在处理的元素节点,并定义了一些变量用于存储当前父节点、根节点等信息。
    • parse函数调用了parseHTML函数,将模版字符串作为参数传递给它,并传递了一个配置对象,其中包含了一些回调函数用于处理解析过程中的不同事件。
    • 在解析过程中,当遇到开始标签时,会调用回调函数start(tag, attrs, unary)。在该回调函数中,会创建一个抽象语法树(AST)节点,并将其添加到当前父节点的子节点列表中。
    • 当遇到结束标签时,会调用回调函数end()。在该回调函数中,会将当前父节点指向栈顶元素的父节点。
    • 解析完成后,返回根节点。
  2. parseHTML函数:

    • parseHTML函数接收一个模版字符串和一个配置对象作为参数。
    • 在解析过程中,使用正则表达式等方式对模版字符串进行扫描,并根据不同情况触发相应的回调函数。
    • 当遇到开始标签时,会调用回调函数start(tag, attrs, unary)。在该回调函数中,会解析标签名、属性和自闭合标签等信息,并将其传递给parse函数。
    • 当遇到结束标签时,会调用回调函数end()
    • 当遇到文本内容时,会调用回调函数chars(text)。在该回调函数中,会处理文本内容,并将其传递给parse函数。
    • 解析完成后,返回解析结果。

综上所述,parse函数是模版编译的入口函数,它创建了一个栈用于保存当前正在处理的元素节点,并通过调用parseHTML函数进行模版解析。而parseHTML函数则负责对模版字符串进行扫描,并根据不同情况触发相应的回调函数来处理开始标签、结束标签和文本内容等信息。通过这两个函数的协作,实现了对模版字符串的解析和构建抽象语法树(AST)的过程。

2. 渲染函数生成

生成渲染函数是模版解析的关键步骤之一。Vue使用了一个名为generate的函数来生成渲染函数的代码。generate函数主要负责将抽象语法树(AST)转化为可执行的JavaScript代码。

 
export function generate(ast, options) {const state = new CodegenState(options)const code = ast? ast.tag === 'script'? 'null': genElement(ast, state): '_c("div")'return {render: `with(this){return ${code}}`,staticRenderFns: state.staticRenderFns}
}

在这段代码中,我们可以看到generate函数接收一个抽象语法树和一些选项作为参数。它使用了一个名为CodegenState的类来保存生成渲染函数的状态,并通过调用genElement函数生成了渲染函数的代码。

  1. 创建代码生成器状态对象:

    • generate函数接收一个抽象语法树(AST)和一些选项作为参数。
    • 在函数内部,创建了一个名为state的代码生成器状态对象,用于保存生成渲染函数的状态和相关信息。
  2. 生成渲染函数代码:

    • generate函数通过调用genElement函数,将抽象语法树转化为渲染函数的代码。
    • 如果传入的抽象语法树为空,则默认生成一个简单的渲染函数代码 _c("div")
  3. 返回结果对象:

    • generate函数返回一个包含渲染函数和静态渲染函数数组的结果对象。
    • 渲染函数通过字符串模板拼接方式生成,并使用 with(this) 包裹以确保在执行时可以访问到组件实例中的数据。
    • 静态渲染函数数组用于优化静态节点,在组件初始化时只需要执行一次。
3. 数据绑定、指令和条件循环处理

在生成渲染函数代码的过程中,还需要处理数据绑定、指令和条件循环等功能。genDatagenDirectives函数主要负责处理元素节点的数据对象和指令相关的代码生成。

 
function genData(el, state) {// ...let data = '{'// ...if (el.directives) {data += genDirectives(el.directives, state)}// ...return data
}function genDirectives(el, state) {const dirs = el.directivesif (!dirs) returnlet res = 'directives:['let hasRuntime = falselet i, l, dir, needRuntimefor (i = 0, l = dirs.length; i < l; i++) {dir = dirs[i]needRuntime = true// ...if (needRuntime) {hasRuntime = trueres += `{name:"${dir.name}",rawName:"${dir.rawName}"${dir.value? `,value:(${dir.value}),expression:${JSON.stringify(dir.value)}`: ''}${dir.arg ? `,arg:${dir.isDynamicArg ? dir.arg : `"${dir.arg}"`}` : ''}${dir.modifiers ? `,modifiers:${JSON.stringify(dir.modifiers)}` : ''}},`}}if (hasRuntime) {return res.slice(0, -1) + ']'}
}function genIf(el, state) {// ...
}function genFor(el, state) {// ...
}

在这段代码中,我们可以看到genData函数用于生成元素节点的数据对象,其中包括了指令的处理。genDirectives函数用于生成指令的代码。genIf函数用于生成条件语句的代码。genFor函数用于生成循环语句的代码。

  1. genData函数:

    • genData函数用于生成元素节点的数据对象。
    • 在函数内部,首先创建一个空字符串变量 data,用于存储生成的数据对象代码。
    • 然后根据元素节点的属性、指令等信息,将相应的代码拼接到 data 中。
    • 如果元素节点包含指令(directives),则调用 genDirectives 函数生成指令相关的代码,并将其拼接到 data 中。
    • 最后返回生成的数据对象代码。
  2. genDirectives函数:

    • genDirectives函数用于生成指令相关的代码。
    • 在函数内部,遍历元素节点上的指令数组,并根据每个指令调用相应的处理函数(如 v-bind、v-on 等)来生成对应指令的代码。
    • 通过遍历指令数组,将每个指令对应处理函数生成的代码拼接到一个字符串变量 res 中。
    • 如果指令包含修饰符(modifiers)且包含 prevent 修饰符,则在最终生成的代码中添加阻止默认事件行为的逻辑。
    • 最后返回生成的指令相关代码字符串。 总结起来,genData函数主要负责生成元素节点的数据对象代码,而genDirectives函数主要负责生成指令相关的代码。通过这两个函数的处理,Vue能够将模版中的元素节点转化为可执行的JavaScript代码,并实现数据绑定、指令操作等功能。这些生成的代码最终会被插入到渲染函数中,并在组件渲染时执行。

总结

模版解析是Vue框架中非常重要的一部分,它负责将组件的模版代码转化为可执行的JavaScript代码。通过编译器对模版进行词法分析、语法分析和生成渲染函数代码等处理,实现了数据绑定、指令、条件和循环等功能。深入理解Vue模版解析的原理和源码实现,有助于我们更好地使用Vue框架进行前端开发。

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

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

相关文章

【文末送书】如何在时间循环里最优决策?

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

OpenAI调查ChatGPT故障;向量搜索的优势与局限

&#x1f989; AI新闻 &#x1f680; OpenAI调查ChatGPT故障&#xff0c;发布新AI产品GPTs和GPT-4 Turbo 摘要&#xff1a;OpenAI的ChatGPT和其他服务出现故障&#xff0c;经过调查后发现是由于DDoS攻击导致的异常流量模式。OpenAI在首届开发者大会上发布了新的AI产品GPTs&am…

CSS3 2D、3D转换

一、CSS3 2D转换&#xff1a; CSS3转换可以对元素进行移动、缩放、转动、拉长或拉伸。 2D变换的方法&#xff1a;translate()、rolate()、scale()、skew()、matrix()。 <style> div { width:200px; height:100px; background-color:red; /* Rotate div */ tran…

Linux命令(120)之tcpdump

linux命令之tcpdump 1.tcpdump介绍 linux命令tcpdump是用来将网络中传送的数据包完全截获下来以进行相关分析&#xff0c;常用的分析工具是wireshark 2.tcpdump用法 tcpdump [参数] tcpdump参数 参数说明-i指定端口-n指定协议-t在输出的每一行不打印时间戳-s抓取数据包时&a…

酷柚易汛ERP - 发货地址管理操作指南

1、应用场景 对发货地址进行管理&#xff0c;使用【物流服务】时的自动获取发货地址。 2、主要操作 打开【资料】-【发货地址管理】新增发货地址。 可以对进行地址设置及管理&#xff0c;点击【新增】可添加新的发货地址信息地址简称方便使用者在选择发货地址时&#xff0c;…

Spring集成MyBatis(自定义类和xml配置文件两种形式)

将mybatis与spring进行整合&#xff0c;主要解决的问题就是讲SqlSessionFactory对象交由spring来管理&#xff0c;所以&#xff0c;该整合&#xff0c;只需要将SqlSessionFactory的对象生成器SqlSessionFactoryBean注册在spring容器中&#xff0c;再将其注入给Dao的实现类即可完…

Lambertian模型(完美漫反射)

这里使用相乘的方式组合光照色和纹理色。根据这个模型,面朝光源的区域光照强度高,纹理色也相应增强。面背光源的区域光照弱,纹理色也被抑制。这样通过光照和纹理的结合,可以合成出具有照明效果的面部颜色,而不仅仅是固定的纹理本身的颜色。相乘方式可以近似实现不同光照方向下面…

TCP怎么实现可靠传输

链接 1&#xff0c;TCP头部的校验和保证获取正确数据&#xff0c;防篡改&#xff1b; 2&#xff0c;序列号和ACK确认机制同于管理数据包&#xff0c;对接收到的数据包进行确认&#xff0c;对没有接收到的数据包进行重传&#xff1b; 3&#xff0c;重传机制&#xff0c;包括超…

MongoDB副本集配置和创建

副本集有三类角色&#xff1a;master(primary)&#xff0c;slave(secondary)&#xff0c;仲裁服务器。 primary是主&#xff0c;只有primary能写入&#xff0c;secondary无法插入数据&#xff0c;且需要声明是slave才能查看数据 一般生产搞三个服务器做一个master和两个slave&a…

树状数组:leetcode307 区域和检索

307. 区域和检索 - 数组可修改 给你一个数组 nums &#xff0c;请你完成两类查询。 其中一类查询要求 更新 数组 nums 下标对应的值另一类查询要求返回数组 nums 中索引 left 和索引 right 之间&#xff08; 包含 &#xff09;的nums元素的 和 &#xff0c;其中 left < ri…

成都优优聚美团代运营:打造高效电商运营的利器

一、引人注目的标题 在繁杂的电商市场中&#xff0c;成都优优聚美团代运营以其专业的服务&#xff0c;为商家提供了一站式的解决方案。那么&#xff0c;这个备受瞩目的代运营平台有何特别之处呢&#xff1f;今天&#xff0c;我们就来一探究竟。 二、平台背景与优势 成都优优聚…

前端如何把图片url地址https://url转成base64

前端如何把图片url地址https://url转成base64 一、直接上代码 一、直接上代码 async getImgImg() {let url await this.base64(this.From.imageData) }&#xff0c; base64(url) {return new Promise(resolve > {const image new Image()// 先设置图片跨域属性image.cros…

JL-03小型气象站气象环境在线监测设备自动上传并保存数据

JL-03小型气象站产品概述 小型气象站用于对风速、风向、雨量、空气温度、空气湿度、太阳辐射、光照强度、土壤温度、土壤湿度、蒸发量、大气压力等气象要素进行现场监测。既可以通过无线通讯将数据传送至云平台&#xff0c;又可以通过配套的数据采集通讯线与计算机进行连接&am…

C/C++内嵌简本语言-LUA

一、LUA简介 Lua [1] 是一个小巧的脚本语言。Lua脚本可以很容易的被C/C 代码调用&#xff0c;也可以反过来调用C/C的函数&#xff0c;这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本&#xff0c;也可以作为普通的配置文件&#xff0c;代替XML,ini等文件格式&#…

1. 深度学习——激活函数

机器学习面试题汇总与解析——激活函数 本章讲解知识点 什么是激活函数&#xff1f; 为什么要使用激活函数&#xff1f; 详细讲解激活函数 本专栏适合于Python已经入门的学生或人士&#xff0c;有一定的编程基础。本专栏适合于算法工程师、机器学习、图像处理求职的学生或人…

一分钟秒懂人工智能对齐

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

C语言的部分逆置

部分逆置 pta c语言&#xff1a; #include <stdio.h>void reverse(int arr[], int start, int end) {while (start < end) {int temp arr[start];arr[start] arr[end];arr[end] temp;start;end--;} }int main() {int n, m;scanf("%d%d", &n, &m…

C++文件的读取和写入

1、C对txt文件的读&#xff0c;ios::in #include<iostream> #include<fstream> using namespace std;int main() {ifstream ifs;ifs.open("test.txt",ios::in);if(!ifs.is_open()){cout<<"打开文件失败&#xff01;"<<endl;}char…

Javaweb之javascript的小案例的详细解析

1.5.4 案例 1.5.4.1 需求说明 鲁迅说的好&#xff0c;光说不练假把式,光练不说傻把式。所以接下来我们需要通过案例来加强对于上述DOM知识的掌握。需求如下3个&#xff1a; 点亮灯泡 将所有的div标签的标签体内容后面加上&#xff1a;very good 使所有的复选框呈现被选中的…

AI毕业设计生成器(基于AI大模型技术开发)

这是一个辅助生成计算机毕业设计的工具&#xff0c;可以自动完成毕业设计的源码。它基于几百个github上面开源的java和python项目&#xff0c;运用tengsorflow技术&#xff0c;训练出了AI大模型。基本实现了计算机毕业设计生成器&#xff0c;能够初步生成Java或python基本源码。…