如何实现一个基于DOM的模板引擎.pdf
《如何实现一个基于DOM的模板引擎.pdf》由会员分享,可在线阅读,更多相关《如何实现一个基于DOM的模板引擎.pdf(22页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、题图:Vincent Guth注:本文所有代码均可在本人的个人项目colon中找到,本文也同步到了知乎专栏可能你已经体会到了 w e所带来的便捷了,相信有一部分原因也是因为其基于DOM 的语法简洁的模板渲染引擎。这篇文章将会介绍如何实现一个基于DOM的模板引擎(就像Vue的模板引擎一样)。Preface开始之前,我们先来看一下最终的效果:coist compiled=Compilc(、h)Heg?,greeting 卜/工 、,greeting:Hello Wor/d11);compiledview/=、工 Hcg?,Hello Wod/kt、Compile实现一个模板引擎实际上就是实现一个编
2、译器,就像这样:const compiled=Coipile(teiplate:St片 八g|Nod%data:Object);coipiled.view/=compiled template首先,让我们来看下Compile内部是如何实现的:/c。叫川e js/*template compiler*Stn.gNode template邺曰M Objectj data*/f 八d o八 Coipile&platej data)if(!(tkis icstanceof Compile)return new Covpile(teiplate,data);this,options=;this,data
3、=data;if(template istaiaceof Node)加s.opticms.teMplate=template;eke if(typeof template=KtH八g)this.optio 八 s.template=doyvify(teplate:else coole.errorCteplate,oialy accept DOM node or string template);)template=tkis.optioias.teplate)wHk(笈 岬/温,(八。de,next)=if(八ode.八odeTgpe=i)/compile CICMC八十 八。pi忆0CMe八t
4、Nodes.call(this,八。de);return Mxt();eke if(node.node叫pe=3)/compile text 八。pile.teKtNo4es.caH(this,node);next。;);this.view=template;template=null;Copile.coipilc=;walk通 过 上 面 的 代 码,可 以 看 到C。叫川e的构造函数主要就是做了一件事-遍 历t e叫;/a t e,然 后 通 过 判 断 节 点 类 型 的 不 同 来 做 不 同 的 编 译 操 作,这里就不介绍 如 何 遍 历 出 呻/加 了,不 明 白 的 话 可 以
5、 直 接 看wa l k函 数 的 源 码,我们着重来看 下 如 何 编 译 这 些 不 同 类 型 的 节 点,以 编 译n o W e m o de T g p e =工的 元 素 节 点 为 例:/*compile element 八。de*仆曰3 Node node*/C o p“e.c o k v p e.e/e 3 0八如o de s =fimetiem(八o de)c o n s t biiadSyibol=、:、;let attributes=slice.call(Mde.attributes),attrNaie-1attrValue=、,directiveNave=、;att
6、ributes.iap(attribute=attv,Nawe=a t t n fe u t e.m e;attrValue=attnbute.value.tniO;if(attKName.i八dexOf(bi八dSgmbol)-O&attrValae/=)diuectiveNaise=att 卜 Nae.slice(bi八 dSgmbol.le 八gth);this.bi 八4DiKective(八。de,express,。八:attrValue,八 M C:di-ectiveNaM。,);Mde.e,ioveA.ttribute(attrNaie);else(tkis.bMdAttHbiA
7、te(八ode,attribute);!););噢 忘 记 说 了,这里我参考了 W e 的 指 令 语 法,就 是 在 带 有 冒 号:的 属 性 名 中(当然 这 里 也 可 以 是 任 何 其 他 你 所 喜 欢 的 符 号),可 以 直 接 写 JavaS cript的 表 达 式,然 后 也 会 提 供 几 个 特 殊 的 指 令,例 如-.text,外。w 等 等 来 对 元 素 做 一 些 不 同 的 操 作。其 实 该 函 数 只 做 了 两 件 事:遍历该节点的所有属性,通过判断属性类型的不同来做不同的操作,判断的标准就是属性名是否是冒号:开头并且属性的值不为空;*绑定相应的
8、指令去更新属性。Directive其次,再看一下Directive内部是如何实现的:import directives from./directives1;import geMrate from/coiM.pile/geMrate1;export default fuMtioia Pirectiv e(o p t i=)Object.assigNthi,options);Object.assigM加s,directivestkis.iaame);this.beforeUpdate&tki.beforeUpdateO;tkis.update&this.updatge-Mratekis.expre
9、iothis.coipile.optio.data);)Directive做了三件事:*注 册 指 令(Object.assigtki,directivtki.Mve);*计算指令表达式的实际值(gecemte(tkis.expressi。八X this.coMpile.optiocs.data);把计算出来的实际值更新到D O M上面(加工叩儿(仇0)。在介绍指令之前,先看一下它的用法:CoMpile.pstotgpe.bi八dDi%ctive=fuMtioi(options 八cw Directived.options)compile:this););Copile.prototype.bi
10、iadAttribute=fuMtioia(八。de,attribute if(!kasliaterpolatioia(attribute.value)|attnbute.value.triiO=)return fake;this.bi八 dDirective(nodCjvavz attribute,expression:pae.textCattnbute.value),attrNae:attribute.iaaiej!);bi八dDirective对Directive做了一1个非常简单的封装,接受二个必填属性:node.:当前所编译的节点,在 Directive的 update方法中用来更新
11、当前节点;name:当前所绑定的指令名称,用来区分具体使用哪个指令更新器来更新视图;*expression:parse 之后的 JavaScript 的表达式。*updater在 Directive 内部我们通过 O bject.directivcsthis.inaie);来注册不同的指令,所以变量directives的值可能是这样的:/directivesexport default/directive、:skowshow:beforeUpdate,(),update(hoA/)tkis.nodestyle.display=show?Mock、:八。八 e、;b)/directive.ite
12、xt、text:(beforeUpdate()update(value)/.卜所以假设某个指令的名字是 ow的话,那 么 Object.assigths,directivesthis.iaaie);就等同于:Object.assigNthis,beforeUpdatc(),update(skow)tkis.MdstyIe.display=skow?block:、八。八c;!);表示对于指令效。w,指令更新器会改变该元素 允 如 的4印 的 值,从而实现对应的功能。所以你会发现,整个编译器结构设计好后,如果我们要拓展功能的话,只需简单地编写指令的更新器即可,这里再以指令te x t举个例子:/d
13、irectivesexport default/directive、:show/show:.当/directive、:text、text:(update(valae)this.ode.textCoteit=value;),);有没有发现编写一个指令其实非常的简单,然后我们就可以这么使用我们的te x t指令了:covst compiled=CoipilcC greeting:Hello World,!);coipiled.view/=sHey?,Hello WorWsgenerate讲到这里,其实还有一个非常重要的点没有提到,就是我们如何把d比 真实数据渲染到模板中,比如Hey?,(greet
14、ing 如何渲染成Hey?,HelloW*/d ,通过下面三个步骤即可计算出表达式的真实数据:*把 Hey?,(greeting 解析成 Heg?,1+greeting 这样的 JavaScript表达式;提取其中的依赖变量并取得所在data中的对应值;利用M W Function)来创建一个匿名函数来返回这个表达式;*最后通过调用这个匿名函数来返回最终计算出来的数据并通过指令的update方法更新到视图中。*parse text/refereiace:https:/gitkub.coi/vuejs/vue/blob/dev/src/coipiler/parser/text-pairserjs
15、:L,2.S-L42.costtagRE=(?:.卜八)力。八 prseftext)if(!tagRE.test(texty)return JSONstricgifg(text);co八st tokens=;let lastMdex=tagRE.lastliadex=O;let iindexj matched;while(,atclaed=tRE.exec(text)i 八 de 乂=Matched.讥 W ex;if(index 心dex)tokc八s.push(JSON.stMngiFg(te)d:.sHce(asi:M,ex,in4cx);tokens,pusla(iatchedl.tn
16、kv();last Index=index+yvatchedO.length)if(lastIndex (H i1+J +colon+1 isawesome.1extract dependency我们会通过下面这个函数来提取出一个表达式中可能存在的变量:coist dope八de八cgRE=/八j Aq*w*-zA-z_Jww*-zA-Z$_Jw*:|(w*a-zA-Z$_Jw*)/g;C0iast global=tnAe-fakeJuNiefinedS(A#JNaNJisNaN,tgpeoPjhdecodeURI decodeUR.lCopoMit1,eModeURC,CModeURlCoi
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 如何 实现 一个 基于 DOM 模板 引擎
限制150内