javascript模板渲染研究笔记(一)

Posted by ngtmuzi on 2015-12-31
班门弄斧

只是一名本分的后端nodejs程序员的我被抓去写前端啦,前端各种东西都搞不懂啊,城里人真是会玩,各种框架各种脚本各种自动化各种模板渲染引擎各种转码,我也是被吓得不敢说话,然而代码还是要写的,研究了一通目前的各种主流框架(angularreactjsvuemeteor以及各种其他)之后,我最终还是决定使用express自带的ejs

即使是各大主流框架,在很大程度上还是离不开jquery,我当然也是如此,使用ejs仅仅是想将一些数据直接在后端渲染好,避免提供过多没必要的ajax接口费时费力。

然而ejs使用中也是各种不爽,在html中加上各种<%%>真是不怎么好看啊,有的时候webstorm显示出来好多错误,排版也炸了,写得真心累,然后想了想,为什么一定要在视图中加上一堆逻辑语句呢,这种写法实在难看(reactjsjsx语法在我眼中当然觉得更难看),然后脑洞一开,我就想到了万能的jquery,jq创建新html元素的语法简直优雅,所有的属性操作都能通过js来完成,就可以远离那些不合常理的模板语言了

因此我开始研究在ejs中加入jq的功能,cheerio模块包含了各种jq的核心功能,它通常的用途是html解析,做抓取之类的功能,然而它构建html元素的函数任然还保留着,因此可以将它加入到ejs里,使用更优雅的语法来构建html——

去翻了一下ejs的源码,大概能理解模板引擎的运行原理了:将原有的模板字符串拆开,将模板符号中包含的代码或表达式进行相应的处理,然后再拼回完整的html……可能说得不是很明白,可以看看这样一段模板语言

1
<h1>{{ 1+1 }}</h1>

所对应的中间函数:

1
2
3
4
5
6
7
function () {
var out = '';
out += '<h1>';
out += escape(1 + 1);
out += '</h1>';
return new String(out);
}

中间函数做了简化,实际上它还在我们看不见的地方做更多复杂的操作,以使我们能使用简单的语言来进行模板渲染。

可以看出来它实际上是做了字符串的拼接操作,模板内包含的表达式也被转义后输出(防止嵌入html标签),那为什么不直接转义成

1
<h1>' + escape(1 + 1) + '</h1>'

这种格式呢?因为需要支持各种看起来高大上的模板语法,如ifeach之类的。


好像有点跑题,刚才的问题是,我如何将cheerio模块加入到ejs中呢?

我们都知道,ejs中如果要将某些变量的值带到模板中渲染,需要在render时传递locals对象,在这个对象里存储所有渲染需要的变量。

但实际上在使用模板引擎时,我们并不会使用名叫locals或者其他类似data之类的变量,而是能直接使用这个变量里提供的属性,原因是,在上面那个函数里,一般还会有类似这样的语句(或者以其他方式实现)

1
2
3
4
5
function(locals){
with(locals){
......
}
}

模板引擎将传入的locals对象使用with语句添加到当前作用域中,使我们能直接通过属性名来取值,因此想要加入$对象,可以直接在传locals对象的时候丢进去:

1
2
var cheerio = require('cheerio');
res.render('index',{ $:cheerio } );

这样子就能实现在ejs里实现类似这样的jq语法了

1
2
3
<% for(var i = 0; i < 10; i++) {%>
<%- $('<a>').text(i.toString()).attr('href','#') %>
<% } %>