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.这个过程包含两个步骤:
本文主要围绕步骤二进行展开,步骤一的话可能会在后续另写一篇进行阐述。
观察上面的产物代码,我们不难发现有三个主要方法: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的实现。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
我正在尝试创建一个流畅的页面,正在由其他一些数据模板构建。 例如: 我有两个。 > =>StackPanel中的按钮和Textblock。如: =>StackPanel中的Textblock和Combobox。如: 在我将它们合并之后,这是第三个模板(类似于: 我会得到一些不流利的东西。可能都是一脉相承的, 或者是两条线,但它会在中间断裂,比如: 按钮文本1\n 文本2\n组合框。 我想要一些像这
问题内容: 我有一个没有Javadoc的大型代码库,我想运行一个程序来编写带有基本Javadoc信息的框架(例如,为每个方法的参数写@param …),所以我只需要填补剩下的空白。 有人知道一个好的解决方案吗? 编辑: JAutodoc是我一直在寻找的东西。它具有Ant任务,一个Eclipse插件,并使用Velocity作为模板定义。 问题答案: eclipse的JAutodoc插件完全可以满足您
问题内容: 如何刷新Django模板中的某个元素? 例: 可以说页面中的其他元素触发了一个应刷新上面div的javascript。有没有办法让django刷新模板中的这个特定元素? 如果没有,我将不得不使用常规的JS或jQuery方法来对div进行猴子补丁,而不要使用django模板层的强大功能。另外,上面的代码是实际模板的简化,我使用了模板的大部分功能,因此猴子修补生成的html将是一场噩梦…
我正在尝试使用Compose设计一个布局,其中包括: 顶部应用栏 正文(内容) 底部应用栏 单击时表示菜单的底页(模式底页) -------顶应用栏------- -主要内容- ------底部压条----- ----模型底板--- Compose提供了3个组件: 脚手架 底板脚手架 模态底板布局 脚手架没有底板属性 BottomSheetScaffold没有BottomAppBar属性 Moda
我一直在读生成树的概念及其类型。这就是我所理解的: 生成树:图G中连接所有顶点的边数最小的子集 最小生成树:它是边权的总和最小的生成树。 现在,这是否意味着,在检索MST时, > 如果我们遇到G中的一条路径,它有更多的边(与其他路径相比),但在边权重总和上的权重最小(与所有其他路径相比),我们将不把它视为MST? MST的概念是否只有在G有多个生成树的情况下才起作用?其他跨树=mst? 谢谢你的帮
表单创建页面工作正常,但我需要表单编辑页面。我想我需要一个att,但我找不到。我怎么做? 管理面板的呈现表单 在此输入图像描述 示例我的数据库行(json) {“type”:“header”,“subtype”:“h1”,“label”:“\u003Ch2\u003E\u0130\u015f Ba\u015fvuru Formu\u003C/h2\u003E”,“access”:false},{“