【手写 Vue2.x 源码】第十二篇 - 生成 ast 语法树-流程说明

news2024/11/15 16:29:10

一,前言

上篇,主要介绍了 vue 数据渲染核心流程,涉及以下几个点:

初次渲染时

  • template 模板被编译为 ast 语法树;
  • 通过 ast 语法树生成 render 函数;
  • 通过 render 函数返回 vnode 虚拟节点;
  • 使用 vnode 虚拟节点生成真实 dom 并进行渲染;

视图更新时

  • 调用 render 函数生成新的 vnode 虚拟节点;
  • 通过 diff 算法对新老 vnode 虚拟节点进行对比;
  • 根据虚拟节点比对结果,更新真实 dom;

本篇,生成 ast 语法树-流程说明


二,Vue 提供的使用方式

1,三种模板写法及优先级

<body>
  <!-- 第一种 -->
  <div id=app>{{message}}</div>
  <script src="./vue.js"></script>
  <script>
    debugger;
    let vm = new Vue({
      el: '#app',
      data() {
      },
      // 第二种
      template:'',
      // 第三种
      render(){}
    });
  </script>
</body>

三种写法的优先级【由高到低】:

  1. 使用 render
  2. 使用 template
  3. 使用元素中的内容;即使用 <div id=app>{{message}}</div> 中的 {{message}}

2,两种数据挂载方式

在 Vue2.x 中,提供了两种挂载方式:

let vm = new Vue({
  // el: '#app',		// 挂载方式一
  data() {
  },
}).$mount('#app');	// 挂载方式 2

当挂载点 vm.$options.el 存在,或直接调用了 Vue 的原型方法 $mount 时,

就会通过Vue 上的原型方法 $mount 对数据进行挂载操作


三,Vue 的原型方法 $mount

<body>
  <div id=app>{{message}}</div>
  <script>
    let vm = new Vue({
      el: '#app',
      data() {...},
    }); 
  </script>
</body>

当 vm.$options.el 存在,或直接调用 Vue 的原型方法 $mount 时,就会对数据进行挂载操作;

所以,设置 vm. o p t i o n s . e l 或 . options.el 或 . options.el.mount,内部都是调用 Vue 原型方法 $mount 进行处理的;

在 $mount 中,拿到 el 挂载点指向的真实 dom 元素,并使用新内容将它替换掉

// src/init.js#initMixin

export function initMixin(Vue) {
  Vue.prototype._init = function (options) {
    const vm = this;
    vm.$options = options;
    
    initState(vm);

    if (vm.$options.el) {
      // 将数据挂载到页面上(此时数据已被观测)
      vm.$mount(vm.$options.el)
    }
  }

  // 支持 new Vue({el}) 和 new Vue().$mount 两种情况
  Vue.prototype.$mount = function (el) {
    const vm = this;
    el = document.querySelector(el); // 获取真实的元素
    vm.$el = el; // vm.$el 为当前页面上的真实元素
  }
}

如何拿到"id = app"对应的元素,outerHTML or innerHTML?

  • outerHTML:<div id=app>{{message}}</div>
  • innerHTML:{{message}}

这里,由于需要使用的新内容替换掉老的内容,
所以,需要使用outerHTML拿到全部内容

再结合不同模板写法的优先级逻辑:

// src/init.js

Vue.prototype.$mount = function (el) {
  const vm = this;
  const opts = vm.$options;
  el = document.querySelector(el);
  vm.$el = el;

  // 如果没有 render, 找 template
  if (!opts.render) {
    // 如果没有 template, 采用元素中的内容
    const template = opts.template;
    if (!template) {
      // 拿到整个元素标签
      console.log(el.outerHTML);
    }
  }
}

运行查看结果:

image.png


四,将模板编译为 ast 语法树

1,compileToFunction

在 vue 中,编译阶段的最终结果是输出 render 函数:

  1. parserHTML:将模板内容编译为 ast 语法树;
  2. generate:再根据 ast 语法树生成为 render 函数;
//  src/compiler/index.js

export function compileToFunction(template) {
  // 1,将模板变成 AST 语法树
  let ast = parserHTML(template);
  // 2,使用 AST 生成 render 函数
  let code = generate(ast);
}

function parserHTML(template) {
  console.log("parserHTML-template : " + template)
}

function generate(ast) {
  console.log("parserHTML-ast : " + ast)
}

在 Vue 中,compileToFunction 方法是 Vue 编译的入口,

完成了以上两个操作,最终将模板编译成为 render 函数;

2,parserHTML

parserHTML 方法:将 HTML 模板编译成为 ast 语法树

注意:这里的 template 指的是 <template> 标签内部的内容,不包含 <template> 标签

compileToFunction(template) 方法,对 html 模板进行处理,需要传入 html 模板:

在 Vue 初始化时:

  • 如果 options 选项中设置了 template,将优先使用 template 内容作为模板: <div id="app"></div>
  • 如果 options 选项没有设置 template,将采用元素内容作为 Html 模板

代码实现

Vue.prototype.$mount = function (el) {
  const vm = this;
  const opts = vm.$options;
  el = document.querySelector(el); // 获取真实的元素
  vm.$el = el; // vm.$el 表示当前页面上的真实元素

  // 如果没有 render, 看 template
  if (!opts.render) {
    // 如果没有 template, 采用元素内容
    let template = opts.template;
    console.log("template = " + template)
    if (!template) {
      // 拿到整个元素标签
      console.log("没有template, el.outerHTML = " + el.outerHTML)
      // 将模板编译为 render 函数
      template = el.outerHTML;
    }else{
      console.log("有template = " + template)
    }
    let render = compileToFunction(template);
    opts.render = render;
  }
}

运行测试:

image.png

至此,我们就拿到了 html 模板

将 html 模板编译为 ast 语法树,用 js 对象的树形结构来描述 HTML 语法

这里就需要对 html 模板进行解析,而解析的方式就是使用正则不断匹配和处理

3,render 函数的重要性

有了 render 函数,当数据变化时,就可以通过 render 函数进行新老对比,

从而可以根据最终对比的结果,再对真实 dom 进行更新


五,结尾

本篇,主要介绍了生成 ast 语法树 - 流程说明,涉及以下几个点:

  • Vue 核心渲染流程回顾
  • 三种模板写法及优先级
  • 两种数据挂载方式
  • Vue 的原型方法 $mount
  • compileToFunction -> parserHTM流程说明

下一篇,生成 ast 语法树-正则说明

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

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

相关文章

基于K8s的DevOps平台实践(三)

文章目录前言1. Jenkins与k8s集成&#x1f351; 插件安装及配置&#x1f351; 演示动态slave pod&#x1f351; Pod-Template中容器镜像的制作&#x1f351; 实践通过Jenkinsfile实现demo项目自动发布到kubenetes环境2. Jenkins集成Sonarqube&#x1f351; sonarqube架构简介&a…

初阶产品经理必看:如何快速进阶B端产品经理

​从去年开始&#xff0c;大批的互联网企业开始转战B端&#xff0c;众多传统企业也早在几年前就开始向互联网转型。 产业互联网的兴起&#xff0c;让一个岗位的潜藏价值正在逐渐爆发&#xff0c;尤其是富有经验的背景&#xff0c;更加让身价越来越高。 这个岗位就是&#xff…

QProcess的非阻塞式用法以及QApplication::processEvents的使用

一、QProcess的阻塞模式QProcess的应用场景非常广泛。可以使用它在qt程序中执行其他进程&#xff0c;并与之进行通信。当使用它执行一些终端命令和操作时&#xff0c;命令和操作往往是需要一定的时间的&#xff0c;这时QProcess本身提供了方法如&#xff1a;waitForStarted() /…

神经网络自适应PID控制及其应用

神经网络自适应PID控制及其应用 总结来自重庆大学宋永瑞教授2022暑期校园行学术会议 1. 研究背景 目前人工智能的发展为很多领域里的研究提供了可延展性&#xff0c;提供了新的研究问题的思路&#xff0c;无人系统和人工智能正走向深度融合&#xff0c;无人系统里具有核心驱动作…

C语言及算法设计课程实验三:最简单的C程序设计——顺序程序设计(四)

C语言及算法设计课程实验三&#xff1a;最简单的C程序设计——顺序程序设计&#xff08;四&#xff09;一、实验目的二、 实验内容2.4、将"China”译成密码三、 实验步骤3.4、顺序程序设计实验题目4&#xff1a;将"China”译成密码的实验步骤3.4.1、变量的定义与赋初…

Android EventBus源码深入解析

前言 EventBus&#xff1a;是一个针对Android进行了优化的发布/订阅事件总线。 github对应地址&#xff1a;EventBus 大家肯定都已经比较熟悉了&#xff0c;这里重点进行源码分析&#xff1b; EventBus源码解析 我们重点从以下三个方法入手&#xff0c;弄清楚register、unre…

关于sql注入这一篇就够了(适合入门)

本文章根据b站迪总课程总结出来,若有不足请见谅 目录 存在sql注入条件 判断数据库类型 注入mysql思路 判断网站是否存在注入点 判断列名数量&#xff08;字段数&#xff09; 文件读写操作 网站路径获取方法 注入类型 按注入点数据类型来分类 根据提交方式分类 猜测查询方式 sql…

(Java高级教程)第三章Java网络编程-第四节:TCP流套接字(ServerSocket)编程

文章目录一&#xff1a;Java流套接字通信模型二&#xff1a;相关API详解&#xff08;1&#xff09;ServerSocket&#xff08;2&#xff09;Socket三&#xff1a;TCP通信示例一&#xff1a;客户端发送什么服务端就返回什么&#xff08;1&#xff09;代码&#xff08;2&#xff0…

量子计算(二十一):Deutsch-Josza算法

文章目录 Deutsch-Josza算法 Deutsch-Josza算法 量子算法是量子计算落地实用的最大驱动力&#xff0c;好的量子算法设计将更快速推动量子计算的发展。 Deutsch-Jozsa量子算法&#xff0c;简称D-J算法&#xff0c;DavidDeutsch和RichardJozsa早在1992年提出了该算法&#xff0…

分布式事务方案分析:两阶段和TCC方案(图+文)

1 缘起 补充事务相关知识过程中&#xff0c; 发现&#xff0c;默认的知识都是基于单体服务的事务&#xff0c;比如ACID&#xff0c; 然而&#xff0c;在一些复杂的业务系统中&#xff0c;采用微服务架构构建各自的业务&#xff0c; 就有了分布式事务的概念&#xff0c;比如&am…

一站式云原生体验|龙蜥云原生ACNS + Rainbond

关于 ACNS 龙蜥云原生套件 OpenAnolis Cloud Native Suite&#xff08;ACNS&#xff09;是由龙蜥社区云原生 SIG 推出的基于 Kubernetes 发行版本为基础而集成的套件能力&#xff0c;可以提供一键式部署&#xff0c;开箱即用&#xff0c;以及丰富的云原生基础能力&#xff0c;…

JProfiler的使用

一、安装 从https://www.ej-technologies.com/download/jprofiler/files获取&#xff0c;如果需要对服务器远程分析&#xff0c;注意服务器版本的jprofiler和windows版本一致。 二、监控一个本地进程 2.1 不使用idea 安装之后&#xff0c;打开jprofiler&#xff0c;点击红框…

电脑蓝屏并提示BAD_POOL_CALLER怎么办?

电脑蓝屏可以说是Windows的常见问题&#xff0c;各种各样的终止代码对应着不同的问题。如果你的蓝屏代码显示BAD_POOL_CALLER&#xff0c;这篇文章就是为你提供的。 可能导致BAD_POOL_CALLER蓝屏错误的原因&#xff1a; 1、硬件或软件不兼容 2、过时或错误的设备驱动程序 3…

DataWorks创建JavaUDF函数全流程

文章目录插件下载创建MaxCompute Studio项目创建MaxCompute Java Module编写Java UDF函数注意说明&#xff1a;这篇文章只是个人记录下&#xff0c;具体步骤都可以在官网找到。推荐看官网文档哈 插件下载 创建MaxCompute Studio项目 启动IntelliJ IDEA&#xff0c;在顶部菜单栏…

1806. 还原排列的最少操作步数

解法一&#xff1a; 根据题目的题目描述进行模拟&#xff0c;遇到偶数iii将arr[i]prem[i/2]arr[i] prem[i/2]arr[i]prem[i/2],遇到奇数iii,将arr[i]prem[(n−1i)/2]arr[i]prem[(n-1i)/2]arr[i]prem[(n−1i)/2] 时间复杂度: O(n2)O(n^2)O(n2), 最多会循环n次空间复杂度&#…

Nginx反向代理使用方法小总结

文章目录一、前言二、反向代理定义重申三、短网址方式代理四、多级域名方式代理五、通配符代理方式总结一、前言 本文只介绍代理转发到一个主机的方式&#xff0c;至于在代理时进行负载均衡大家需要自己尝试&#xff0c;也比较简单&#xff0c;在本专栏前面文章提到过&#xf…

(二)Redis概述与安装

目录 一、概述 1、特性 2、应用场景 二、安装 三、启动 1、前台启动&#xff08;不推荐&#xff09; 2、后台启动&#xff08;推荐&#xff09; 四、redis关闭 五、redis相关知识介绍 一、概述 1、特性 Redis是一个开源的key-value存储系统。和Memcached类似&#x…

TOOM舆情分析监控管理系统集成,舆情监控系统监测那些人群?

当前&#xff0c;互联网已成为思想文化信息的集散地和社会舆论的扩大器&#xff0c;舆情监控新闻、论坛博客、聚合新闻等等&#xff0c;做好舆情监控&#xff0c;至于监测那些人群&#xff0c;舆情分析监控是非常必要的&#xff0c;接下来我们简单了解TOOM舆情分析监控管理系统…

接口协议之抓包分析 TCP 协议

TCP 协议是在传输层中&#xff0c;一种面向连接的、可靠的、基于字节流的传输层通信协议。环境准备对接口测试工具进行分类&#xff0c;可以如下几类&#xff1a;网络嗅探工具&#xff1a;tcpdump&#xff0c;wireshark代理工具&#xff1a;fiddler&#xff0c;charles&#xf…

《移动通信》多章节部分重要习题(简答、单选、判断)

调制技术在移动通信中的作用&#xff1f; 调制有两个目的: 1 )经过调制可以使基带信号变换为带通信号。选择需要使用的载波频率 ( 简称载频 ) ,可以把信号的频谱从开始的频段转移到到所需要的频段上,从而使传输信号适应信道的要求,或是可以把许多个输入信号合起来应用于多路传…