原文链接:点这里
几年之前就有人提出过,随着浏览器的强大MVC会前移,一个程序的不再是由一个个独立的、每次请求由服务器生成的页面组成,而是第一次请求生成的HTML&JS&CSS驻留在浏览器中,然后通过REST和服务器进行数据交互。这并不是一个什么新的架构,如果我们用Flex开发一个Web程序的话,其实一般都用的都是这种方式。浏览器的进步确实在推进一部分偏重应用的Web程序往这个方向发展,现在JavaScript的SPA框架已经百花齐放了,如《JavaScript宝座:七大框架论剑》里所说:
加载整个页面,然后再“渐进增强”以添加动态行为,这种构建Web应用的方式已经不够好了。要想让应用加载快,反应灵敏,而且又引领潮流,必须彻底检讨你的开发手段。真正的JavaScript应用必须有适当的数据模型,并具备客户端渲染能力,而绝不仅仅是服务器处理数据再加上一些Ajax和jQuery代码那么简单。
在SPA应用中几乎都用到了客户端模板,似乎服务器模板已经没有用武之地了,确实有很多人认为混合使用客户端模板和服务器模板是一个糟糕的实践。如何处理好服务器和客户端之间的关系确实是个问题,stackoverflow上有人问了类似的问题:《Typical Angular.js workflow and project structure (with Python Flask)》。
在实际的应用 中往往还是展示为主的页面和部分应用为主的页面(这样的一个页面往往是一个SPA)的结合,所有的页面还是有一些可以共享的东西的——比如页头、页尾已经用户特定的信息,这部分用服务器端来处理还是比较简单,所以混合使用服务器模板和客户端模板目前来说还是一个务实的做法。
好了,言归正传。无论是服务器模板还是客户端模板大家使用的分隔符也就那么几种,比如现在正在用的Jinja2(Flask的默认模板)和AngularJS默认的变量分隔符都是"{{}}",当它们一起使用的时候自然就会产生冲突。
Django里的分割符也是"{{}}",所以可以参考:《AngularJS with Django - Conflicting template tags》里给出的解决方案,简而言之,这个方案就是利用AngularJS的一个API改变他的分隔符:
myModule.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('{[{');
});
但这样做的缺点是如果你使用了其它的AngularJS的插件,而这个插件的模板中使用了"{{}}"这样的分隔符(写死在模板中了),那么就会出问题。
那反过来想想,我们可以不改客户端模板的分隔符,而是去改服务器模板的分隔符,当然Jinja2也是支持的:
env = Environment(variable_start_string="${", variable_end_string="}")
这样可以把Jinja2的变量分隔符改为“${}”,当然还可以做更多的设置。但这样做不只对服务器端模板的编写者不习惯,更严重的问题是一些针对这种模板的编辑器也认不出这个符号了。
除了上述两种非此即彼的方案,也许二者的分隔符都不做修改是更好的方法。Jinja2文档里有讲原样输出一个分隔符的方法:
{{ '{{' }}
如果输出一大段文字,还有更好的方法:
{% raw %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endraw %}
当然这样的模板会难看些,但也是比较折中的方法了。
有朋友在评论里提到的方法也是不错的:
在jinja2中使用"{{空格"就可以区分了
app.jinja_env.variable_start_string = '{{ '
app.jinja_env.variable_end_string = ' }}'
在angularjs中使用{{}}就可以了,这样服务器端和客户端都不需要修改。
多谢卓之威的评论。