• 【大前端之前后分离02】前端模板嵌套问题


    回顾

    接上文:【大前端之前后分离01】JS前端渲染VS服务器端渲染,我们探讨了为什么要做前后分离,以及前端渲染需要解决的问题,最后提出了自己的解决方案:

    前端代码编译形成两套代码:①前端发布版本 + ②服务器端脚本

    这个想法借鉴了fis plus的smarty模块化思维,以及reactJS编译运行的概念,上次初步论证了其可行性,也遗留了一些问题,其中比较关键的问题是:

    前端模块嵌套问题

    我们在一个模板中又有一个widget,在子模板中又有一个widget,父模块与子模块中有数据依赖,或者子模块为一个循环,循环却依赖父模块某个值,这个便很麻烦。

    举个例子来说,我们首页引入了一个商品模块,商品类型模块为一循环模块,里面又有子模块:

    index首页模块:

    1 <div id="type_widget_wrapper">
    2   <script type="text/javascript">
    3     render('text!./template/type.html', './model/type', './controller/type', 'type_widget_wrapper');
    4   </script>
    5 </div>

    type模块:

     1 <ul id="type_id">
     2     <% for (var i = 0, len = data.length; i < len; i++) { %>
     3     <li class="type js_type">
     4         <h2><%=data[i].name%></h2>
     5         <ul class="product_list">
     6             <% for (var j = 0, len1 = data[i].product.length; j < len1; j++) { %>
     7                 <li class="product">
     8                     <%=data[i].product[j].name%>
     9                 </li>
    10             <% } %>
    11         </ul>
    12     </li>
    13     <% } %>
    14 </ul>

    可以看到,其中有第二次循环迭代的将该类型的商品信息读出,如果我们想将商品信息模块化的,这里便出现了模块嵌套情况:

     1 <ul id="type_id">
     2     <% for (var i = 0, len = data.length; i < len; i++) { %>
     3     <li class="type js_type">
     4         <h2><%=data[i].name%></h2>
     5         <ul class="product_list">
     6         <div id="product_list_widget_wrapper">
     7           <script type="text/javascript">
     8             render('text!./template/product_list.html', './model/product_list', './controller/product_list', 'product_list_widget_wrapper');
     9           </script>
    10         </div>
    11         </ul>
    12     </li>
    13     <% } %>
    14 </ul>

    这里暂时不考虑子模块中还有异步数据请求问题,我们将列表对应的模板放到了单个文件中:

    1 <% for (var j = 0, len1 = data[i].product.length; j < len1; j++) { %>
    2     <li class="product">
    3         <%=data[i].product[j].name%>
    4     </li>
    5 <% } %>

    这里的循环解析便是我们今天研究的重点,因为前端模块至少需要两个条件:

    ① 唯一的dom容器

    ② 能获取父级模块的相关数据

    为了解决这个问题,我这里提出了迭代模块的概念。

    迭代模块

    所谓迭代模块,便是用于数据内嵌形式,并且处于循环中的模块,比如上述例子,我整个type模板就变成了这样(这里为最简形式):

     1 <ul id="type_id">
     2   <% for (var i = 0, len = data.length; i < len; i++) { %>
     3   <li class="type js_type">
     4     <h2>
     5       <%=data[i].name%></h2>
     6     <ul class="product_list">
     7 
     8       <div id="data_inner_widget_wrapper_<%=i %>">
     9         <script type="text/javascript">
    10           iteratorRender({
    11             index: typeof <%=i%> == 'string' ? '<%=i%>' : <%=i%>,
    12             value: <%=JSON.stringify(data[i])%>,
    13             name: 'data_inner'
    14           });
    15         </script>
    16       </div>
    17 
    18     </ul>
    19   </li>
    20   <% } %>
    21 </ul>

    这个是编译过后形成的前端代码,最初是这样的:

     1 <ul id="type_id">
     2   <% for (var i = 0, len = data.length; i < len; i++) { %>
     3   <li class="type js_type">
     4     <h2>
     5       <%=data[i].name%></h2>
     6     <ul class="product_list">
     7         <%iteratorWidget({
     8           index: <%=i%>,
     9           value: <%=JSON.stringify(data[i])%>,
    10           name: 'data_inner',
    11         }); %>
    12     </ul>
    13   </li>
    14   <% } %>
    15 </ul>
    1 <%iteratorWidget({
    2   index: <%=i%>, //索引,整数或者字符串
    3   value: <%=JSON.stringify(data[i])%>, //对应数据对象,字符串或者json对象
    4   name: 'data_inner',
    5 }); %>

    这个时候前端需要实现iteratorRender方法,首先前端模板将上述代码解析结束后是这个样子的:

     1 "<ul id="type_id">
     2   
     3   <li class="type js_type">
     4     <h2>
     5       电脑</h2>
     6     <ul class="product_list">
     7 
     8       <div id="data_inner_widget_wrapper_0">
     9         <script type="text/javascript">
    10           iteratorRender({
    11             index: typeof 0 == 'string' ? '0' : 0,
    12             value: {"id":1,"name":"电脑","product":[{"name":"戴尔"},{"name":"苹果"},{"name":"联想"},{"name":"华硕"}]},
    13             name: 'data_inner'
    14           });
    15         </script>
    16       </div>
    17 
    18     </ul>
    19   </li>
    20   
    21   <li class="type js_type">
    22     <h2>
    23       书籍</h2>
    24     <ul class="product_list">
    25 
    26       <div id="data_inner_widget_wrapper_1">
    27         <script type="text/javascript">
    28           iteratorRender({
    29             index: typeof 1 == 'string' ? '1' : 1,
    30             value: {"id":2,"name":"书籍","product":[{"name":"三国演义"},{"name":"西游记"},{"name":"红楼梦"},{"name":"水浒传"}]},
    31             name: 'data_inner'
    32           });
    33         </script>
    34       </div>
    35 
    36     </ul>
    37   </li>
    38   
    39   <li class="type js_type">
    40     <h2>
    41       游戏</h2>
    42     <ul class="product_list">
    43 
    44       <div id="data_inner_widget_wrapper_2">
    45         <script type="text/javascript">
    46           iteratorRender({
    47             index: typeof 2 == 'string' ? '2' : 2,
    48             value: {"id":3,"name":"游戏","product":[{"name":"仙剑1"},{"name":"仙剑2"},{"name":"仙剑3"},{"name":"仙剑4"}]},
    49             name: 'data_inner'
    50           });
    51         </script>
    52       </div>
    53 
    54     </ul>
    55   </li>
    56   
    57 </ul>
    View Code
     1 <li class="type js_type">
     2   <h2>
     3     电脑</h2>
     4   <ul class="product_list">
     5 
     6     <div id="data_inner_widget_wrapper_0">
     7       <script type="text/javascript">
     8         iteratorRender({
     9           index: typeof 0 == 'string' ? '0' : 0,
    10           value: { "id": 1, "name": "电脑", "product": [{ "name": "戴尔" }, { "name": "苹果" }, { "name": "联想" }, { "name": "华硕"}] },
    11           name: 'data_inner'
    12         });
    13       </script>
    14     </div>
    15 
    16   </ul>
    17 </li>

    然后前端方法的实现为:

     1 //最简单实现,仅考虑渲染,不严谨
     2 var iteratorRender = function (opts) {
     3   var name = opts.name;
     4   var index = opts.index;
     5   var data = typeof opts.value == 'string' ? JSON.parse(opts.value) : opts.value;
     6   var wrapperId = name + '_widget_wrapper_' + index;
     7   var template = 'text!./template/' + name + '.html';
     8   var controller = './controller/' + name;
     9 
    10   require([template, controller], function (tpl, view) {
    11     var html = $(_.template(tpl)(data));
    12     var wrapper = $('#' + wrapperId);
    13     html.insertBefore(wrapper);
    14     wrapper.remove();
    15     //执行控制器
    16     view.init();
    17   });
    18 }

    然后代码运行,逻辑跑通了:

    结语

    由于最近工作强度上来了,解决了前端渲染时候的模板嵌套问题,一直拖到了今天,服务器端的模板嵌套更好处理,该方案后续会继续细化

  • 相关阅读:
    C++后台开发校招面试常见问题
    算术表达式的前缀,中缀,后缀相互转换
    Redis键值对数据库的设计与实现
    C++经典面试题(最全,面中率最高)
    C++开发工程师面试题大合集
    C++中常用的设计模式
    C++中const修饰函数,函数参数,函数返回值的作用
    C++main函数的参数介绍以及如何在main函数前执行一段代码
    Windows系统下安装tensorflow+keras深度学习环境
    第十三周学习总结
  • 原文地址:https://www.cnblogs.com/yexiaochai/p/4492170.html
Copyright © 2020-2023  润新知