让Mustache支持简单的IF语句
转载:https://blog.csdn.net/iteye_16732/article/details/82070065
Mustache是一种Logic-less templates.不支持if这类条件判断是Logic-less的显著特征之一.Mustache的另一个特征是体积小,不依赖其他前端类库,在浏览器端和NodeJS中都可以运行.
并非Logic-less.Mustache的体积小,无依赖,前后兼容才是我们当前的项目选择这套模板系统的真正原因.没有IF有时候感觉并不给力,所以就想办法简单扩展下Mustache,让其具有一些通用的条件判断能力.
比如如下的应用场景,我们需要根据某一字段的值,决定输出有意义的中文,并用颜色加以修饰.
status=="P" ==> <b style="color:green">通过</b>
status=="W" ==> 等待
status=="R" ==> <b style="color:red">拒绝</b>
Logic-less模板实现这个功能就需要在数据上下功夫,如下.
data = {
list:[
{ id:"1",status"P"},
{ id:"2",status"W"},
{ id:"3",status"R"}
],
statusRenderer:function(){
if(this.status=="P"){
return '<b style="color:green">通过</b>'
}else if(this.status=="W"){
return '等待'
}else{
return '<b style="color:red">拒绝</b>'
}
}
}
这里的statusRenderer就是在数据这边扩展做的工作,{{{statusRenderer}}}在渲染时,this指向当前context,在取得status之后,经过判断,return正确的渲染字符串.
于是配合下面的模板就可以满足我们的要求
<ul>
{{#list}}
<li>ID:{{id}},status:{{{statusRenderer}}}</li>
{{/list}}
</ul>
项目是很复杂的,如果需要写无数statusRenderer那会非常累,所以我想Renderer功能强大,在遇到各种特殊情况时,单独写一下未尝不可,但是想上面这种常见需求是需要抽象一下的.
比如我们希望如下这样的模板,完成同样的需求.
<ul>
{{#list}}
{{#if(status==P)}}<li>ID:{{id}},status:<b style='color:green'>通过</b></li>{{/endif}}
{{#if(status==W)}}<li>ID:{{id}},status:等待</li>{{/endif}}
{{#if(status==R)}}<li>ID:{{id}},status:<b style='color:red'>拒绝</b></li>{{/endif}}
{{/list}}
</ul>
这个改造看起来一定是会伤筋动骨的,因为完全打破了{{#xxx}}{{/xxx}}这种Mustache的嵌套模式.改过之后Mustache就不再是Mustache了.
于是我们在这里妥协下,把{{/endif}}改为{{/if(status==W)}},这样{{#if(status==W)}}{{/if(status==W)}}就配起对来了.
接下来我们就只要想办法从模板中把这类标签正则出来,然后为这类配对自动添加Renderer即可.
模板变成了下面这样:
<ul>
{{#list}}
{{#if(status==P)}}<li>ID:{{id}},status:<b style='color:green'>通过</b></li>{{/if(status==P)}}
{{#if(status==W)}}<li>ID:{{id}},status:等待</li>{{/if(status==W)}}
{{#if(status==R)}}<li>ID:{{id}},status:<b style='color:red'>拒绝</b></li>{{/if(status==R)}}
{{/list}}
</ul>
而输入给to_html方法的数据则变成如下这样(里边的Render为自动生成):
data = {
list:[
{ id:"1",status"P"},
{ id:"2",status"W"},
{ id:"3",status"R"}
],
//下面Renderer为自动生成.
"if(status==P)":function(){
if(this.status=="P"){
return true;
}
return false;
},
"if(status==W)":function(){
if(this.status=="W"){
return true;
}
return false;
},
"if(status==R)":function(){
if(this.status=="R"){
return true;
}
return false;
}
}
整个改造的大体流程如下,首先从模板中取出if(x.y.z==abc)这样的key,然后自动生成以"if(x.y.z==abc)"为名字的Renderer.全部代码如下:
function addFns(template, data){
var ifs = getConditions(template);
var key = "";
for (var i = 0; i < ifs.length; i++) {
key = "if(" + ifs[i] + ")";
if (data[key]) {
continue;
}
else {
data[key] = buildFn(ifs[i]);
}
}
}
function getConditions(template){
var ifregexp_ig = /\{{2,3}[\^#]?if\((.*?)\)\}{2,3}?/ig;
var ifregexp_i = /\{{2,3}[\^#]?if\((.*?)\)\}{2,3}?/i;
var gx = template.match(ifregexp_ig);
var ret = [];
if (gx) {
for (var i = 0; i < gx.length; i++) {
ret.push(gx[i].match(ifregexp_i)[1]);
}
}
return ret;
}
function buildFn(key){
key = key.split("==");
var res = function(){
var ns = key[0].split("."), value = key[1];
var curData = this;
for (var i = ns.length - 1; i > -1; i--) {
var cns = ns.slice(i);
var d = curData;
try {
for (var j = 0; j < cns.length - 1; j++) {
d = d[cns[j]];
}
if (cns[cns.length - 1] in d) {
if (d[cns[cns.length - 1]].toString() === value) {
return true;
}
else {
return false;
}
}
}
catch (err) {
}
}
return false;
};
return res;
}
// new to_html for exports
function to_html(template, data){
addFns(template, data);
return Mustache.to_html.apply(this, arguments);
}
看起来这样做的好处是保持了Mustache的配对风格,并且继续无缝支持原生的嵌套以及否定等语法.
但看起来模板挺丑的,性能损耗也一定是有不少的.
后续的扩展,我想elseif肯定不能支持了,if中带"与""或"判断倒是还方便添加的.
当然还可以做很多扩展,比如给数组增加一些内置属性如"_index_", "_first_", "_last_", "_odd_", "_even_".
Mustache仍然足够简单,它本身就具有循环和否定判断等特性,增加了IF后,稍微加了点逻辑,但能少写很多Renderer.
重要的是我们依然保有我们所看重的东西:体积小,无依赖,前后兼容.
在我的项目里破坏了Logic-less是我的事情并不接受批判,但请大家根据自己实际情况谨慎选择.
刚刚接触Mustache,各种特性还在学习摸索中,现在看起来Lambda和子模板等特性,让Mustache的JS实现小巧却功能强大.
或许今天的需求还有更好的解决方案,如果有同学知道还望不吝赐教.
让Mustache支持简单的IF语句的更多相关文章
- 一条简单的更新语句,MySQL是如何加锁的?
看如下一条sql语句: # table T (id )) delete : MySQL在执行的过程中,是如何加锁呢? 在看下面这条语句: : 那这条语句呢?其实这其中包含太多知识点了.要回答这两个问题 ...
- 『片段』OracleHelper (支持 多条SQL语句)
C# 调用 Oracle 是如此尴尬 >System.Data.OracleClient.dll —— .Net 自带的 已经 过时作废. >要链接 Oracle 服务器,必须在 本机安装 ...
- Memcache仅仅支持简单数据类型
Memcache仅仅支持简单数据类型 ,复杂数据类型需要应用自己处理 从数据库当中取出数据[User [id=1, username=guowuxin, password=guowuxin], Use ...
- Tornado 模板支持“控制语句”和“表达语句”的表现形式
Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) > 2 %}.表达语句是使用 {{ 和 }} 包起来的,例 ...
- [20190328]简单探究sql语句相关mutexes.txt
[20190328]简单探究sql语句相关mutexes.txt --//摘要:http://www.askmaclean.com/archives/understanding-oracle-mute ...
- sql最简单的查询语句
-- 2 **************************************************** -- 最简单的查询语句 -- 2.1 ----------------------- ...
- ThinkPHP框架 系统规定的方法查询数据库内容!!同时也支持原生的SQL语句!
<?php namespace Admin\Controller; use Think\Controller; class MainController extends Controller{ ...
- 四种简单的sql语句(增删改查语句)
四种简单的sql语句(增删改查语句) 一.插入语句 insert into [table] ([column],[column],[column]) values(?,?,?) 二.删除语句 dele ...
- tp5 r3 一个简单的SQL语句调试实例
tp5 r3 一个简单的SQL语句调试实例先看效果核心代码 public function index() { if (IS_AJAX && session("uid&quo ...
随机推荐
- Java内存分配机制
内存分配,主要指的是在堆上的分配, 一般的,对象的内存分配都是在堆上进行,但现代技术也支持将对象拆成标量类型(标量类型即原子类型,表示单个值,可以是基本类型或String等),然后在栈上分配,在栈上分 ...
- 学习笔记60—SPSS
一.直方图上显示曲线图:打开SPSS ----> 导入数据 ----> 描述统计 ----> 分析 ----> 频率 ----> 图表 ----> 直方图(勾上在直 ...
- LeetCode--015--三元之和(java)
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...
- CSS font-family字体大合集
在写文字内容占大篇幅的页面是,总是会面临着改变字体的需求,以下为font-family常用合集以及一部分文字效果: windows常见内置中文字体 字体中文名 字体英文名 ...
- Android基础知识(一)
前言 前言 从软件测试最终目的发现问题缺陷来看,Findyou比较认同一个观念,测试的能力大致可以划分成三个能力层次:发现问题.定位问题.预防问题.有机会探讨一下这个分类. 发现问题各种方式方法,比如 ...
- lumion的基本操作,天气系统,景观系统。5.25
1.打开场景,按住鼠标右键可以选择方向. 2.向前移动:W,向后移动S,亦可以用鼠标滚轮向前或者向后滚.向左A向右D, 3.Q提升视角,E下降视角. 4.鼠标滚轮点下去,进行提升和下降视角.左右移动, ...
- liunx文件操作 文件压缩
文件备份和压缩命令 在Linux中,常用的文件压缩工具有gzip,bzip2,zip. 'bzip2'是最理想的压缩工具,它提供了最大限度的压缩. 'zip'兼容好,windows也支持. bzip2 ...
- django中的ORM介绍和字段及字段参数
Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...
- 【转载】Spring Cloud全家桶主要组件及简要介绍
https://blog.csdn.net/xlgen157387/article/details/77773908
- python常见错误
最近刚刚接触Python,为了养成好习惯,遇到了诸多的问题,林林总总,在这里简单记录下: 编写简单的python语句时: module level import not at top of file ...