
一晃眼已经2016年了,隔了几个月没有总结写文章好想抽死自己。而且要准备校招了得放点东西到这里呀。
寒假又来See实习了。大三上学期也断断续续帮See写一些页面:http://biouscowork.sinaapp.com/,每次活动都各种熬夜,后面才慢慢改善。接下来写一些这些页面的总结和坑。这次是接口渲染。
Ajax & Cgi
CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。
这就是经常说的接口啦。cgi这个词是看过某大大写的页面后才发现原来应该这么叫。一般请求接口返回的就是需要渲染的数据了,比如这个:getActivity 。一般后台给的都是json,如果是字符串的话就前端解析一下就好了。
一般一个活动页面是这样的流程:前端重构好,拿到接口后就直接渲染。运营提供数据给后台开发,后台改接口返回的数据。不是之前的php框架那样服务器渲染好后吐出html,用接口的html一般没有太多数据,所以要是接口请求失败了或者请求时间比较长页面会有很长的空白,体验没那么好。自己总结一下优缺点吧:
优点:
- 简单的前后端分离,后端只提供数据,前端专注渲染
 
- 容易控制一些异步的数据展现
 
- 可以通过接口的代理简单实现本地开发,不需要太依赖后端环境
 
缺点:
- 请求上多了接口,渲染工作放在了客户端,性能不太好
 
- 和后台联调需要一些时间,沟通成本增加
 
- 不利于SEO,不过这种做的一般是活动页面,SEO并不是很重要
 
- js代码需要一定的组织
 
渲染的几种方式
实习的时候有幸见到几种不同的方法渲染数据,总结一下,大概三种:jQuery的DOM操作,前端模板引擎,MV*框架
DOM操作
用jquery操作数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 
  | var li = t.li_sample.clone(true).attr('name','li_row').attr('f_id', f.f_id).show(); if (f.u_id == see.user.uid) {     li.find('[name=delete]').attr('f_id', f.f_id).show(); } li.find('[name=img]').attr('src', f.f_headimg).on('click', function () {     var u_url = see.isInApps()?"see://userCenter?u_id="+dt.circle.owner_id:"http://m.seeapp.com";     window.location.href = u_url; }); li.find('[name=nick]').text(f.f_username); li.find('[name=comment]').text(f.f_comment); if(f.u_isdaren == 1) {     li.find('.daren-logo').show(); } if(f.u_tag) {     li.find('[name=tag]').text(f.u_tag).css('display', 'inline-block'); } if(f.circle) {     li.find('[name=circle_name]').text(f.circle.cir_name);     var url = see.getUrlPrefix() + "/static/detail/circle.html?cir_id=" + f.circle.cir_id;     li.find('.circle').show().attr('data-href',url).on('click', function(event) {         event.preventDefault();         window.location.href = url;     }); } 
  | 
嗯,第一次实习见到的代码是这样的。当时觉得好厉害,原来jQuery可以这么用,之前都只会用来写动画。后面见到其他的方法后觉得这种方法一般般咯:
- 需要不断的查找dom节点,觉得影响性能。而且一般通过属性name来查找,但是name属性一般用来给后台传值用,觉得可以用其他的字段来代替。
 
- 需要判断字段的合法性。当某个字段不存在时特别容易报错,影响接下来的数据渲染。
 
- 渲染和其他的操作混在一起了:比如添加类名、绑定事件
 
- 优点是比较直观易懂。适合小片的数据展示
 
- 主要流程是,复制一个html中的父节点,在里面渲染数据后append到容器中。
 
还有一种同样是操作dom的方式:
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 
  | collection: function(ret){     if (render._check(ret)){         var goodsClass = ret.data.item_list;         var $collections = $('.mod_collection');         goodsClass.forEach(function(array,index){             var virtualDOMs = array.map(render._collectionBox);             $collections.eq(index).append(virtualDOMs);         });     } }, _collectionBox: function(collectionObj){     var $collectionBox = $('<div class="mod_collection_box"></div>');     var itemInfo = collectionObj.item_info.map(render._collectionItem);     var $collectionGoods = $('<div class="box_content"></div>');     $collectionGoods.html(itemInfo);     $collectionBox.append(render._collectionBanner(collectionObj.base_info));     $collectionBox.append($collectionGoods);     return $collectionBox; }, 
  | 
用map函数返回做好的dom片段加入页面中,每个片段用$生成。感觉代码比上面的要好看的多。
- 没有了dom的查找,用$生成html片段,但js里就包含太多html的东西了
 
- 事件绑定都放到所有节点渲染完毕后来做
 
- 很多数据结构必须为数组,不过这个和后台约定就好了
 
刚开始做的活动基本都是这么干,然后js随随便便就67百行了:双11预热,当时不懂封装什么的,代码只是简单的分了点层。后面学习了其他的写法,有几点可以进行改进:
- 将所有请求的接口放到一个对象:
1 2 3 4 
  | t.RequestURL = {     'getUserdetail': t.apiDomain + '/user/getUserdetail',     'getFormalData': t.apiDomain + '/act1111_formal/getFormalData' }; 
  | 
 
 
或者这么写:
1 2 3 4 5 
  | var cgi = {     getOneDayLimitData: function(){         return $.getJSON(apiDomain + '/index.php/actBlack5/getOneDayLimitData');     } }; 
  | 
第二种方法可以很优雅的在函数里这么用:
1 
  | cgi.getOneDayLimitData().done(render.limit); 
  | 
一股浓浓的angular的味道!缺点是用zepto就不能这么链式调用了。不过zepto改一下源码应该也能这么干。另外全部写在一起也方便对接口路径做一些处理,比如加上时间戳:
1 
  | getActivity: '/actXmas/getActivity' + '?timestamp=' + (new Date()).getTime(), 
  | 
不用在函数里一个个找来修改了。
- 能放到对象的不止接口,像一些cdn处理的后缀也可以放进去
1 2 3 4 5 6 7 8 
  | t.ImageSnipper = {     group : "?imageView2/2/w/600/q/80",     collection : "?imageView2/2/w/600/q/80",     collection_item : "?imageView2/2/w/200/q/80",     recommend : "?imageView2/2/w/300/q/80",     top_item: "?imageView2/2/w/300/q/80",     bottom_item: "?imageView2/2/w/300/q/80" }; 
  | 
 
 
以前全部写在渲染的函数里真的太麻烦了,不方便维护和修改,当然这里也只是简单封装,后面angular可以配置得更灵活点
前端模板引擎
这个就类似后台的MVC的V了。只不过放到js来做。这是在另一个师兄的代码里看到的,第一眼又是惊艳到我:
1 2 3 4 5 
  | tags = $(Util.tmpl(tplCoverStr, {     collection_info: data[i].collection_info,     url:see.getUrlPrefix() + "/static/detail/collection.html?id=" })); wrapper.appendChild(tags[0]); 
  | 
js真的超级简单,然后看一下html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
  | <script type="text/template" id="tpl-collection-items"> <div class="j-slide-list com-wrap" curindex="0" size="<%= pageSize %>"> <% for (var i = 0, k = 0; i < list.length; i+=3, k++) { %>     <ul class="com-list com<%= k %>" classindex="<%= k %>">         <% for (var j = 0; j < 3; j++) { %>             <% if (i + j >= list.length) { continue;} %>             <li>                                  <a href="<%=url + list[i + j].item_id %>">                     <b style="background-image:url(<%= list[i + j].item_imgurl %>)"></b>                     <p><%= list[i + j].item_name %></p>                     <p class="dis"><%= list[i + j].item_comments %></p>                     <p class="price">                         <span class="preferential">¥<%= list[i + j].price %></span>                         <span class="original">¥<%= list[i + j].ori_price %></span>                     </p>                 </a>             </li>         <% } %>     </ul> <% } %> </div> </script> 
  | 
和后台的MVC基本一样,用原生的js的语法进行循环赋值判断什么的。
- 适合直白的列表展示,没有太多的条件逻辑。如果条件很多的话html会很多很乱
 
- 可以在html里放一份注释的渲染后的样本例子,先改动栗子再改模板,方便调试
 
- 一些数据需要在js里进行处理后再进行渲染,或者改成适合渲染的结构
 
- 不好做数据有效性验证,最好渲染前处理一遍数据
 
- 数据出错不好做定位
 
在开发里试过一两次,用的模板引擎好像是腾讯出品,选其他的大概也不会差太多:
1 2 3 4 5 6 
  | var top_item_list = {     data: data.top_item_list }; _html = template('p_top_item_list',top_item_list); document.getElementById('T_top_item_list').innerHTML = _html; $(".m-goods-card04").find('img[name=lazyload]').on('load',resizeImg); 
  | 
用模板引擎的函数处理一遍html和数据,返回html片段,直接塞进父容器就好,后面再进行一些事件绑定。
MV*框架
现在都用这个来做活动了,用的是Angular。暑假实习的时候用这个写了后台,活动没有选他是因为觉得有点杀鸡用牛刀了。但是后面公司又来了一位大大,全部用Angular写,然后我也尝试了一下,发现效果真的很好~每次请求一次服务,在html里写好指令就ok了
1 2 3 4 5 6 7 8 9 10 11 12 
  |     BackEndList.getYearIndex().success(function (data) {         if (data.result == 1) {             $scope.data = data.data;             $scope.cur_firstList = data.data.firstList[$scope.cur_first_date];             $scope.typeList = data.data.typeList;             $scope.typeSubList = filterSubList($scope.typeList);         } else {             console.log('warn');         }     }) }; 
  | 
终于不用花太多精力在写数据渲染上了TAT。后面再单独写一篇关于Angular的总结。总之用了这个,代码量真的会少,工作效率真的提高了!另外事件绑定也没有以前那么麻烦,更直白一点了。
今天周末来公司加班。然而老大说需求改了,先不做。啊,今天就在公司坐着吹吹水写这个东西了。