Angular如何由模板生成DOM树的方法


Posted in Javascript onDecember 23, 2019

Angular等现代Web框架极大的提高了开发效率,比如我们经常会在开发过程中写出类似下面的代码:

<div>
  {{title}}
</div>

export class AppComponent {
 title = 'angular';
}

这种模板写法并不是HTML原生支持的,那么Angular又是如何转换这些代码,并显示成我们期望的界面呢? 首先我们来看看Angular把上述代码编译成什么样子:

...省略了其他代码
 i0.ɵɵelementStart(0, "div");
 i0.ɵɵtext(1, " hello angular\n");
 i0.ɵɵelementEnd()
 ...省略了其他代码

可以看到,Angular把我们写的模板编译成指令的方式,然后通过这些指令生成对应的HTML.这个过程包含两个步骤:

  1. 把模板编译成上面的产物
  2. 执行产物代码生成HTML

本文主要围绕步骤二进行展开,步骤一的话可能会在后续另写一篇进行阐述。

观察上面的产物代码,我们不难发现有三个主要方法:elementStart、text、elementEnd.从它们的命名不难推测,这三个方法的作用分别是开始生成标签、内容赋值、闭合标签。下面我们来尝试自己实现这几个方法,最简单的基础版本大概会是这样:

let currentNode: Node | null = null;
let currentParent: Node | null = null;

function patch(host: Node | DocumentFragment, render: () => void): void {
  currentNode = host;
  render();
}

function elementOpen(tagName: string): void {
  currentParent = currentNode;
  const element = document.createElement(tagName);
  currentParent!.appendChild(element);
  currentNode = element;
}

function text(textContent: string): void {
  currentNode!.textContent = textContent;
}

function elementEnd(tagName: string): void {
  currentNode = currentParent;
  currentParent = currentNode!.parentNode;
}

然后在HTML中可以这样使用:

<div id="container"></div>
 <script>
 function render() {
  elementOpen('div');
  text('div content');
   elementOpen('p');
   text('p content');
   elementEnd('p');
  elementEnd('div');
 }
 patch(document.getElementById('container'), render);
 </script>

上述代码中,text方法参数都被写固定了,实际生成的代码可能类似于text(Comp.title)这种形式。那么既然是以变量的形式赋值,当用户进行操作的时候,更新这个变量的值,岂不是又要完全重新执行一遍patch函数么?我们知道DOM操作是耗时的,当我们的项目较大时,如果不采取优化措施,势必会影响框架性能。为此我们很容易想到的一个优化思路,在再次执行patch函数时,如果DOM节点已经存在我们就重复利用,不再去重新创建并插入DOM树。基于这个思路,我们来更新一下代码:

let currentNode: Node | null = null;
let currentParent: Node | null = null;


function patch(host: Node | DocumentFragment, render: () => void): void {
  currentNode = host;
  render();
}

function elementOpen(tagName: string): void {
  currentParent = currentNode;

  const firstChild = (currentParent as Element).firstElementChild;
  if (firstChild && firstChild.tagName.toLowerCase() === tagName) {
    currentParent = firstChild;
    return;
  }

  const element = document.createElement(tagName);
  currentParent!.appendChild(element);
  currentNode = element;
}

function text(textContent: string): void {
  if (currentNode!.textContent !== textContent) {
    currentNode!.textContent = textContent;
  }
}

function elementEnd(tagName: string): void {
  currentNode = currentParent;
  currentParent = currentNode!.parentNode;
}

本文所述代码,只是表述Angular由模板生成dom树的大致思路。具体的Angular做了许多优化,而且它实现细节也和本文有区别。不同于现今较为流行的virtual DOM实现方式,Angular这种实现思路不需要单独创建中间DOM对象,减少了内存分配。对此感兴趣的读者可以自行去看Angular的实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
初学JavaScript第二章
Sep 30 Javascript
jQuery对html元素取值与赋值的方法
Nov 20 Javascript
javascript移出节点removeChild()使用介绍
Apr 03 Javascript
js实现tab切换效果实例
Sep 16 Javascript
JavaScript使用DeviceOne开发实战(四)仿优酷视频应用
Dec 02 Javascript
jquery实现页面常用的返回顶部效果
Mar 04 Javascript
vue.js表格组件开发的实例详解
Oct 12 Javascript
详解ES6语法之可迭代协议和迭代器协议
Jan 13 Javascript
jQuery实现的页面详情展开收起功能示例
Jun 11 jQuery
vue-auto-focus: 控制自动聚焦行为的 vue 指令方法
Aug 25 Javascript
使用Layui搭建后台管理界面的操作方法
Sep 20 Javascript
JS实现横向轮播图(初级版)
Jun 24 Javascript
Vue+Node实现的商城用户管理功能示例
Dec 23 #Javascript
java遇到微信小程序 &quot;支付验证签名失败&quot; 问题解决
Dec 22 #Javascript
webpack打包html里面img后src为“[object Module]”问题
Dec 22 #Javascript
node.js事件轮询机制原理知识点
Dec 22 #Javascript
javascript实现fetch请求返回的统一拦截
Dec 22 #Javascript
详解vue-router 动态路由下子页面多页共活的解决方案
Dec 22 #Javascript
判断JavaScript中的两个变量是否相等的操作符
Dec 21 #Javascript
You might like
php 正则 过滤html 的超链接
2009/06/02 PHP
PHP封装的MSSql操作类完整实例
2016/05/26 PHP
用php+ajax新建流程(请假、进货、出货等)
2017/06/11 PHP
PHP实现随机发扑克牌
2020/04/22 PHP
JavaScript使用prototype定义对象类型(转)[
2006/12/22 Javascript
jquery isEmptyObject判断是否为空对象的函数
2011/02/14 Javascript
jquery和ajax的关系详细介绍
2013/11/29 Javascript
jquery教程限制文本框只能输入数字和小数点示例分享
2014/01/13 Javascript
document.forms用法示例介绍
2014/06/26 Javascript
微信小程序 网络API 上传、下载详解
2016/11/09 Javascript
JS如何设置iOS中微信浏览器的title
2016/11/22 Javascript
JavaScript实现256色转灰度图
2017/02/22 Javascript
jQuery插件MovingBoxes实现左右滑动中间放大图片效果
2017/02/28 Javascript
JavaScript关联数组用法分析【概念、定义、遍历】
2017/03/15 Javascript
微信小程序swiper组件用法实例分析【附源码下载】
2017/12/07 Javascript
vue2.0 实现页面导航提示引导的方法
2018/03/13 Javascript
微信小程序实时聊天WebSocket
2018/07/05 Javascript
详解angular2如何手动点击特定元素上的点击事件
2018/10/16 Javascript
JS桶排序的简单理解与实现方法示例
2019/11/25 Javascript
微信小程序后端实现授权登录
2020/02/24 Javascript
NodeJS多种创建WebSocket监听的方式(三种)
2020/06/04 NodeJs
在Python中字典根据多项规则排序的方法
2019/01/21 Python
学python安装的软件总结
2019/10/12 Python
django框架auth模块用法实例详解
2019/12/10 Python
python中spy++的使用超详细教程
2021/01/29 Python
canvas线条的属性详解
2018/03/27 HTML / CSS
SEPHORA丝芙兰德国官方购物网站:化妆品、护肤品和香水
2020/01/21 全球购物
西班牙鞋子和箱包在线销售网站:zapatos.es
2020/02/17 全球购物
用你熟悉的语言写一个连接ORACLE数据库的程序,能够完成修改和查询工作
2012/06/11 面试题
文体活动实施方案
2014/03/27 职场文书
中学感恩教育活动总结
2015/05/05 职场文书
学雷锋献爱心活动总结
2015/05/11 职场文书
初中英语教师个人工作总结2015
2015/07/21 职场文书
2016年最美孝心少年事迹材料
2016/02/26 职场文书
承诺书应该怎么写?
2019/09/10 职场文书
JavaScript 实现页面滚动动画
2021/04/24 Javascript