
正文
根据json数据和HTML模板,渲染嵌套的HTML
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
2020-12-22 11:53:23 星期二
场景, HTML模板是多个div嵌套, 里边有列表, 也有键值对, 与之匹配的有一个json数据, 需要根据json去渲染这个HTML DOM
示例截图:
1. HTML模板
1 <div id="test">
2 <div>{aa}</div>
3 <div>{bb}</div>
4 <div>{mm}</div>
5 <div>
6 <div class="cc">{n} : {v} : {mm}</div>
7 </div>
8 <div class="dd">
9 <div>{d1}</div>
10 <div>{d2}</div>
11 <div>{mm}</div>
12 <div class="d3">{x} : {y} : {mm}</div>
13 </div>
14 </div>
2. json数据 (注意mm, 这个键在内外层都有)
1 {
2 'aa' : 'aa',
3 'bb' : 'bb',
4 'mm' : '1',
5 'cc' : [
6 {'n': 'n1', 'v' : 'v1', 'mm' : '2' },
7 {'n': 'n2', 'v' : 'v2', 'mm' : '2' },
8 {'n': 'n3', 'v' : 'v3', 'mm' : '2' },
9 ],
10 'dd' : [
11 'd1' : 'd1',
12 'd2' : 'd2',
13 'd3' : [
14 {'x' : 'x1', 'y': 'y1', 'mm': '4'},
15 {'x' : 'x2', 'y': 'y2', 'mm': '4'},
16 {'x' : 'x3', 'y': 'y3', 'mm': '4'},
17 ],
18 'mm' : '3'
19 ]
20 };
3. 渲染方法 (注意, 适用了递归, 先渲染内层的数据, 再渲染外层数据, 防止内外层有相同的键导致覆盖)
1 /**
2 * @param node HTML DOM节点, 注意不是string
3 * @param arr json数组 注意是数组类型
4 * @return string 返回HTML字符串, 注意不是DOM节点
5 */
6 function repeatNode(node, arr) {
7
8 let out = [];
9 for (let i=0; i<arr.length; i++) {
10 let tmp = node.outerHTML;
11 console.log(tmp);
12 tmp = tmp.replace(/\s/g, ' '); //去掉回车换行, 减少空白符
13
14 let map = arr[i];
15 console.log(map);
16
17 //先渲染内层的数组
18 for (let j in map) {
19 if (map[j] instanceof Array) { //数组, 递归替换
20 let subNode = node.querySelector('.'+j);
21 let subHtml = repeatNode(subNode, map[j]); //递归
22 let subTpl = subNode.outerHTML.replace(/\s/g, ' ');
23 tmp = tmp.replace(subTpl, subHtml);
24
25 }
26 }
27
28 //再渲染内层的对象
29 for (let j in map) {
30
31 if (map[j] instanceof Object && !(map[j] instanceof Array)) { //对象, 递归替换
32
33 let subNode = node.querySelector('.'+j);
34 let subHtml = repeatNode(subNode, [map[j]]); //递归
35 let subTpl = subNode.outerHTML.replace(/\s/g, ' ')
36 tmp = tmp.replace(subTpl, subHtml);
37
38 }
39 }
40
41 //最后渲染外层的键值对/字符串
42 for (let j in map) {
43 if (typeof map[j] === 'string') { //字符串, 直接替换
44 let re = new RegExp('{' + j + '}', 'g');
45 tmp = tmp.replace(re, map[j]);
46
47 }
48 }
49
50 out.push(tmp);
51 }
52
53 return out.join('');
54 }
4. 全部代码
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=yes">
6 <title>Title</title>
7 <script src="/static/jquery.min.js"></script>
8 <style type="text/css">
9 div {margin:8px; margin-left: 10px; padding: 3px; border-radius: 5px; width: 80%;}
10 #test {background-color: #eee;}
11 .cc {background-color: #ccc;}
12 .dd {background-color: #aaa;}
13 .d3 {background-color: #888;}
14 </style>
15 </head>
16 <body>
17 <div id="target"></div>
18
19 <!-- 注意{mm}是内外层都有 -->
20 <template id="tpl">
21 <div id="test">
22 <div>{aa}</div>
23 <div>{bb}</div>
24 <div>{mm}</div>
25 <div>
26 <div class="cc">{n} : {v} : {mm}</div>
27 </div>
28 <div class="dd">
29 <div>{d1}</div>
30 <div>{d2}</div>
31 <div>{mm}</div>
32 <div class="d3">{x} : {y} : {mm}</div>
33 </div>
34 </div>
35 </template>
36
37 <script type="text/javascript">
38 let arr = [{"aa":"aa","bb":"bb","mm":"1","cc":[{"n":"n1","v":"v1","mm":"2"},{"n":"n2","v":"v2","mm":"2"},{"n":"n3","v":"v3","mm":"2"}],"dd":{"d1":"d1","d2":"d2","d3":[{"x":"x1","y":"y1","mm":"4"},{"x":"x2","y":"y2","mm":"4"},{"x":"x3","y":"y3","mm":"4"}],"mm":"3"}}];
39
40 let tpl = document.getElementById('tpl').innerHTML;
41 let node = htmlToNode(tpl);
42 //console.log(node);
43
44 document.getElementById('target').innerHTML = repeatNode(node, arr);
45
46 /**
47 * @param node HTML DOM节点, 注意不是string
48 * @param arr json数组 注意是数组类型
49 * @return string 返回HTML字符串, 注意不是DOM节点
50 */
51 function repeatNode(node, arr) {
52
53 let out = [];
54 for (let i=0; i<arr.length; i++) {
55 let tmp = node.outerHTML;
56 console.log(tmp);
57 tmp = tmp.replace(/\s/g, ' '); //去掉回车换行, 减少空白符
58
59 let map = arr[i];
60 console.log(map);
61
62 //先渲染内层的数组
63 for (let j in map) {
64 if (map[j] instanceof Array) { //数组, 递归替换
65 let subNode = node.querySelector('.'+j);
66 let subHtml = repeatNode(subNode, map[j]); //递归
67 let subTpl = subNode.outerHTML.replace(/\s/g, ' ');
68 tmp = tmp.replace(subTpl, subHtml);
69
70 }
71 }
72
73 //再渲染内层的对象
74 for (let j in map) {
75
76 if (map[j] instanceof Object && !(map[j] instanceof Array)) { //对象, 递归替换
77
78 let subNode = node.querySelector('.'+j);
79 let subHtml = repeatNode(subNode, [map[j]]); //递归
80 let subTpl = subNode.outerHTML.replace(/\s/g, ' ')
81 tmp = tmp.replace(subTpl, subHtml);
82
83 }
84 }
85
86 //最后渲染外层的键值对/字符串
87 for (let j in map) {
88 if (typeof map[j] === 'string') { //字符串, 直接替换
89 let re = new RegExp('{' + j + '}', 'g');
90 tmp = tmp.replace(re, map[j]);
91
92 }
93 }
94
95 out.push(tmp);
96 }
97
98 return out.join('');
99 }
100
101 function htmlToNode(html) {
102 let div = document.createElement('div');
103 let pos = html.indexOf('<'); //避免开头有空白
104 div.innerHTML = html.substring(pos);
105 return div.firstChild;
106 }
107
108
109 </script>
110
111 </body>
112 </html>
推荐几个自己开发的小工具:
SummerPHP一款简洁的PHP框架, 支持多种方式渲染HTML, 支持接口化
zbJSTool好用的js库集合, 单页面路由框架, 前端生成分享图等等
microStore 单页面, 小巧, 适用移动端的个人商店系统








