zoukankan      html  css  js  c++  java
  • 根据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;  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>
    View Code

    推荐几个自己开发的小工具:

    SummerPHP 一款简洁的PHP框架, 支持多种方式渲染HTML, 支持接口化

    zbJSTool 好用的js库集合, 单页面路由框架, 前端生成分享图等等

    microStore 单页面, 小巧, 适用移动端的个人商店系统

  • 相关阅读:
    Ubuntu 16 安装redis客户端
    crontab 参数详解
    PHP模拟登录发送闪存
    Nginx配置端口访问的网站
    Linux 增加对外开放的端口
    Linux 实用指令之查看端口开启情况
    无敌的极路由
    不同的域名可以指向同一个项目
    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error
    Redis 创建多个端口
  • 原文地址:https://www.cnblogs.com/iLoveMyD/p/14172238.html
Copyright © 2011-2022 走看看