【大前端之前后分离02】前端模板嵌套问题
2015-05-10 13:51
288 查看
回顾
接上文:【大前端之前后分离01】JS前端渲染VS服务器端渲染,我们探讨了为什么要做前后分离,以及前端渲染需要解决的问题,最后提出了自己的解决方案:前端代码编译形成两套代码:①前端发布版本 + ②服务器端脚本
这个想法借鉴了fis plus的smarty模块化思维,以及reactJS编译运行的概念,上次初步论证了其可行性,也遗留了一些问题,其中比较关键的问题是:
前端模块嵌套问题
我们在一个模板中又有一个widget,在子模板中又有一个widget,父模块与子模块中有数据依赖,或者子模块为一个循环,循环却依赖父模块某个值,这个便很麻烦。
举个例子来说,我们首页引入了一个商品模块,商品类型模块为一循环模块,里面又有子模块:
index首页模块:
<div id="type_widget_wrapper"> <script type="text/javascript"> render('text!./template/type.html', './model/type', './controller/type', 'type_widget_wrapper'); </script> </div>
type模块:
<ul id="type_id"> <% for (var i = 0, len = data.length; i < len; i++) { %> <li class="type js_type"> <h2><%=data[i].name%></h2> <ul class="product_list"> <% for (var j = 0, len1 = data[i].product.length; j < len1; j++) { %> <li class="product"> <%=data[i].product[j].name%> </li> <% } %> </ul> </li> <% } %> </ul>
可以看到,其中有第二次循环迭代的将该类型的商品信息读出,如果我们想将商品信息模块化的,这里便出现了模块嵌套情况:
<ul id="type_id"> <% for (var i = 0, len = data.length; i < len; i++) { %> <li class="type js_type"> <h2><%=data[i].name%></h2> <ul class="product_list"> <div id="product_list_widget_wrapper"> <script type="text/javascript"> render('text!./template/product_list.html', './model/product_list', './controller/product_list', 'product_list_widget_wrapper'); </script> </div> </ul> </li> <% } %> </ul>
这里暂时不考虑子模块中还有异步数据请求问题,我们将列表对应的模板放到了单个文件中:
<% for (var j = 0, len1 = data[i].product.length; j < len1; j++) { %> <li class="product"> <%=data[i].product[j].name%> </li> <% } %>
这里的循环解析便是我们今天研究的重点,因为前端模块至少需要两个条件:
① 唯一的dom容器
② 能获取父级模块的相关数据
为了解决这个问题,我这里提出了迭代模块的概念。
迭代模块
所谓迭代模块,便是用于数据内嵌形式,并且处于循环中的模块,比如上述例子,我整个type模板就变成了这样(这里为最简形式):<ul id="type_id"> <% for (var i = 0, len = data.length; i < len; i++) { %> <li class="type js_type"> <h2> <%=data[i].name%></h2> <ul class="product_list"> <div id="data_inner_widget_wrapper_<%=i %>"> <script type="text/javascript"> iteratorRender({ index: typeof <%=i%> == 'string' ? '<%=i%>' : <%=i%>, value: <%=JSON.stringify(data[i])%>, name: 'data_inner' }); </script> </div> </ul> </li> <% } %> </ul>
这个是编译过后形成的前端代码,最初是这样的:
<ul id="type_id"> <% for (var i = 0, len = data.length; i < len; i++) { %> <li class="type js_type"> <h2> <%=data[i].name%></h2> <ul class="product_list"> <%iteratorWidget({ index: <%=i%>, value: <%=JSON.stringify(data[i])%>, name: 'data_inner', }); %> </ul> </li> <% } %> </ul>
<%iteratorWidget({ index: <%=i%>, //索引,整数或者字符串 value: <%=JSON.stringify(data[i])%>, //对应数据对象,字符串或者json对象 name: 'data_inner', }); %>
这个时候前端需要实现iteratorRender方法,首先前端模板将上述代码解析结束后是这个样子的:
"<ul id="type_id"> <li class="type js_type"> <h2> 电脑</h2> <ul class="product_list"> <div id="data_inner_widget_wrapper_0"> <script type="text/javascript"> iteratorRender({ index: typeof 0 == 'string' ? '0' : 0, value: {"id":1,"name":"电脑","product":[{"name":"戴尔"},{"name":"苹果"},{"name":"联想"},{"name":"华硕"}]}, name: 'data_inner' }); </script> </div> </ul> </li> <li class="type js_type"> <h2> 书籍</h2> <ul class="product_list"> <div id="data_inner_widget_wrapper_1"> <script type="text/javascript"> iteratorRender({ index: typeof 1 == 'string' ? '1' : 1, value: {"id":2,"name":"书籍","product":[{"name":"三国演义"},{"name":"西游记"},{"name":"红楼梦"},{"name":"水浒传"}]}, name: 'data_inner' }); </script> </div> </ul> </li> <li class="type js_type"> <h2> 游戏</h2> <ul class="product_list"> <div id="data_inner_widget_wrapper_2"> <script type="text/javascript"> iteratorRender({ index: typeof 2 == 'string' ? '2' : 2, value: {"id":3,"name":"游戏","product":[{"name":"仙剑1"},{"name":"仙剑2"},{"name":"仙剑3"},{"name":"仙剑4"}]}, name: 'data_inner' }); </script> </div> </ul> </li> </ul>
View Code
<li class="type js_type"> <h2> 电脑</h2> <ul class="product_list"> <div id="data_inner_widget_wrapper_0"> <script type="text/javascript"> iteratorRender({ index: typeof 0 == 'string' ? '0' : 0, value: { "id": 1, "name": "电脑", "product": [{ "name": "戴尔" }, { "name": "苹果" }, { "name": "联想" }, { "name": "华硕"}] }, name: 'data_inner' }); </script> </div> </ul> </li>
然后前端方法的实现为:
//最简单实现,仅考虑渲染,不严谨 var iteratorRender = function (opts) { var name = opts.name; var index = opts.index; var data = typeof opts.value == 'string' ? JSON.parse(opts.value) : opts.value; var wrapperId = name + '_widget_wrapper_' + index; var template = 'text!./template/' + name + '.html'; var controller = './controller/' + name; require([template, controller], function (tpl, view) { var html = $(_.template(tpl)(data)); var wrapper = $('#' + wrapperId); html.insertBefore(wrapper); wrapper.remove(); //执行控制器 view.init(); }); }
然后代码运行,逻辑跑通了:
结语
由于最近工作强度上来了,解决了前端渲染时候的模板嵌套问题,一直拖到了今天,服务器端的模板嵌套更好处理,该方案后续会继续细化相关文章推荐
- C++的类模板的问题(实现文件和头文件放在一起), 因为模板不支持分离编译
- 不依赖服务端渲染模板,前端实现模板渲染加载问题的一些思考。
- 02_嵌套矩形(DAG最长路问题)
- ThinkPHP问题收集:模板中使用U方法时无法嵌套大括号,For标签,插入数据,新增的表字段缓存问题
- 1kb的前端HTML模板解析引擎,不限于嵌套、循环、函数你能想到的解析方式
- 关于模板分离编译问题
- smarty 模板内嵌套 css js问题
- 前端后端分离,怎么解决SEO优化的问题呢?
- 前端框架vue.js系列(8):嵌套元素、导入外部文件作为模板
- 《模板的分离编译问题》
- 【大前端之前后分离01】JS前端渲染VS服务器端渲染
- 前后端分离的j2ee的web项目,使用vue方式,即{{}}方式批量传入前端参数,遇到一个一个问题,页面上一开始有{{}},怎么处理?
- 模板的分离编译问题
- 前端开发学习之——利用模板实现涉及url问题时的bug分析及解决(chrome源码)
- doT.js——前端javascript模板引擎问题备忘录
- easyUI的日期时间组合框简单模板+日期时间格式更改+前端传过去日期后台接收不到问题
- [置顶] c++使用模板时.h和.cpp分离产生的问题分析和解决方案
- Discuz X2.5 前端模板自定义嵌入点问题
- doT.js——前端javascript模板引擎问题备忘录
- 前端与服务器分离开发出现跨域问题,jsonp与gulp-connect注意点,angularjs改造