平时的工作中,经常会遇到渲染列表的需求,比如下面的代码
1 2 3 4 5 6 7 8 9
| var data = [{id: 1, name: 'hanger'}, {id: 2, name: 'Alice'}] var tableContent = '' data.forEach(function (obj) { tableContent += '<tr>' + '<th >' + obj.id + '</th>' + '<th>' + obj.name + '</th>' + '</tr>' }) console.log(tableContent)
|
向上面这样写一个字符串十分繁琐,而且不可复用。那么有什么办法可以解决这样的问题呢?
我们都知道js的replace()函数可以实现字符串的替换,replace()第二个参数可以为函数,在开启列表模板引擎进化之旅之前需要先理解replace方法。
现在我要利用replace()的强大能力来解决上面这个问题。直接上最初的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function tplEngine1(tpl, obj) { var tpl = tpl.replace(/<%([^%>]+)?%>/g, function(a, b) { var b = b.trim() return obj[b] }) return tpl } var tpl = '<tr>' + '<th><%id%></th>' + '<th><%name%></th>' + '</tr>' var tableContent = '' data.forEach(function (obj) { tableContent += tplEngine1(tpl, obj) }) console.log(tableContent)
|
在控制台打印一下,你会得到同样的结果,是不是觉得这样的字符串简单多了呢。
但是上面这个版本的模板引擎还是最简单的、功能最弱的版本,随着需求的增加,我们需要不断改进它。
解决两层数据对象
1 2 3 4 5 6 7 8 9 10 11 12
| function tplEngine2(tpl, obj) { var tpl = tpl.replace(/<%([^%>]+)?%>/g, function(a, b) { var b = b.trim() if (/\./.test(b)) { var arr = b.split('.') return obj[arr[0]][arr[1]] } else { return obj[b] } }) return tpl }
|
解决得到的数据是数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function tplEngine3(tpl, obj, separator) { var separator = separator || ',' var tpl = tpl.replace(/<%([^%>]+)?%>/g, function(a, b) { var b = b.trim() if (/\./.test(b)) { var arr = b.split('.') if (obj[arr[0]][arr[1]] instanceof Array) { return obj[arr[0]][arr[1]].join(separator) } else { return obj[arr[0]][arr[1]] } } else { if (obj[b] instanceof Array) { return obj[b].join(separator) } else { return obj[b] } } }) return tpl }
|
避免显示undefined
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| function tplEngine4(tpl, obj, fruitless, separator) { var fruitless = fruitless || '' var separator = separator || ',' var tpl = tpl.replace(/<%([^%>]+)?%>/g, function(a, b) { var b = b.trim() if (/\./.test(b)) { var arr = b.split('.') if (obj[arr[0]][arr[1]] instanceof Array) { if (obj[arr[0]][arr[1]].length == 0) { return fruitless } else { return obj[arr[0]][arr[1]].join(separator) } } else { return obj[arr[0]][arr[1]] if (obj[arr[0]][arr[1]]) {} else { return fruitless } } } else { if (obj[b] instanceof Array) { if (obj[b].length == 0) { return fruitless } else { return obj[b].join(separator) } } else { if (obj[b]) { return obj[b] } else { return fruitless } } } }) return tpl }
|
填充变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| function tplEngine5(tpl, obj, fruitless, separator) { var fruitless = fruitless || '' var separator = separator || ',' var tpl = tpl.replace(/<@([^@>]+)?@>/g, function(match, $1) { var $1 = $1.trim() return eval($1) }) var tpl = tpl.replace(/<%([^%>]+)?%>/g, function(a, b) { var b = b.trim() if (/\./.test(b)) { var arr = b.split('.') if (obj[arr[0]][arr[1]] instanceof Array) { if (obj[arr[0]][arr[1]].length == 0) { return fruitless } else { return obj[arr[0]][arr[1]].join(separator) } } else { return obj[arr[0]][arr[1]] if (obj[arr[0]][arr[1]]) {} else { return fruitless } } } else { if (obj[b] instanceof Array) { if (obj[b].length == 0) { return fruitless } else { return obj[b].join(separator) } } else { if (obj[b]) { return obj[b] } else { return fruitless } } } }) return tpl }
|
添加过滤函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| function tplEngine6(tpl, data, separator) { if (!separator && separator !== 0) { separator = ',' }
function print($1, filter) { if (/\./.test($1)) { var arr2 = $1.split('.') var arr3 = data[arr2[0]][arr2[1]] if (arr3 instanceof Array) { if (filter) { for (var i = 0; i < arr3.length; i++) { arr3[i] = filter(arr3[i]) } } return arr3.join(separator) } else { if (filter) { arr3 = filter(arr3) } return arr3 } } else { var arr4 = data[$1] if (arr4 instanceof Array) { if (filter) { for (var i = 0; i < arr4.length; i++) { arr4[i] = filter(arr4[i]) } } return arr4.join(separator) } else { if (filter) { arr4 = filter(arr4) } return arr4 } } }
var tpl = tpl.replace(/<@([^@>]+)?@>/g, function(match, $1) { var $1 = $1.trim() if (/\|/.test($1)) { var arr = $1.split('|') var filter = eval(arr[1]) var variate = eval(arr[0]) return filter(variate) } else { return eval($1) } })
var tpl = tpl.replace(/<%([^%>]+)?%>/g, function(match, $1) { var $1 = $1.trim() if (/\|/.test($1)) { var arr = $1.split('|') var filter = eval(arr[1]) return print(arr[0], filter) } else { return print($1) } }) return tpl }
|
有了过滤函数,就可以处理没值的情况了,因此去掉了fruitless参数,封装了print()函数使代码更加简洁。至此,列表模板引擎已经可以处理大部分工作中遇到的情况了。