藏地传奇真言专题简单小结

先来个传送门:藏地传奇-真言专题。话说搞这个专题也折腾了不少时间,看似简单的页面,实际也隐藏着大大小小的坑。下面请听我一一道来。

一、先从布局说起

真言专题页采用的布局是屡见不鲜的瀑布流。其实当时一接到这个需求的时候,第一反应是Github上搜插件库,因为关于瀑布流的JQ库实在是太多了。像KISSY的waterfall,像@Sebobo 的Wookmark-jQuery,像jQuery Masonry等,都是很简单易用的库。但体验过其中几个DEMO之后,发现其实都不符合需求的预期,于是决定自己写一个。虽说写得有点挫,但效果还算不错,

在我的理解看来,瀑布流布局主要有三类方式可以实现,分别是绝对定位,浮动排列以及CSS3定义。这三种方式其实并没有绝对的优劣好坏之分。使用绝对定位的方法,能使得每个方块的位置更容易安排,受到HTML结构的影响较少,但要使用JS大量的进行位置计算,性能上会有损失。使用浮动的话,更多的是CSS主导,布局简单易用,避免了大量的JS位置计算,但方块位置受到的约束较大。CSS3方法实现的话IE系列就明显不给力了,或许现阶段并不适合业务大环境。

而这次的藏地需求中,每个方块的大小是固定的,主要有三种规格,使用浮动布局实现起来更加简单快捷,于是我采用了浮动布局的方法进行设计。父容器使用三列等宽的DIV,然后每次加载时候通过JS计算三列的高度,然后把新的方块插进最短的父容器当中。因为父容器的宽度是固定的,然后每个方块的大小也是固定的模板,所以直接插入父容器就可以了,无需计算每个方块的位置。

关于瀑布流布局的扩展阅读:

二、方块模板和组合

此次专题中,方块模板分几种,分别是有图片的大方块(329X219),有图片的小方块(164X109),无图纯文字的大方块(329X219),无图纯文字的小方块(164X109) 。根据设计稿,这些方块出现的组合只有三种,分别是一个大方块单独出现,两个小方块同时出现以及四个小方块同时出现。

关于滚动加载,一开始先入为主的想法就是通过AJAX返回数据数组,然后通过拼接字符串凑出HTML,然后把拼出来的HTML插入到DOM当中去。一开始写DEMO的时候,拼凑字符串的确是见效最快的方法,但这并不适合生产环境。因为拼凑HTML带来了很多的问题。首先是代码格式问题,用JS拼出的HTML可谓是一坨一坨的,即使加上合理的缩进,看上去也感到很不舒服。而且这样也不符合重构的思想——表现,行为和结构三者的分离,导致可维护性变得很差。然后,这样的做法还存在着XSS的风险,因为简单的拼凑容易忽略了HTML危险字符的转义。

这个时候,使用模板就是不二的选择。而且优秀的JS模板也很多,诸如Mustache,Handlebars,Juicer等等。而且模板写起来也更加纯粹,避免了JS和HTML混写带来的不爽。因为之前一直有使用Handlebarsjs这个模板,于是此次藏地的专题也就自然而言的选择了它。Handlebars其实算是一个带逻辑的模板,这次用在这里显得有点牛刀杀鸡了。因为方块的模板用不到逻辑判断。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<script id=“big-box-noimg-tpl”type=“text/x-handlebars-template”>

<div class=‘b-box’data-tag=‘nopic’>

<div class=‘cont-only’>

<h3 class=‘y-title-only’>{{title}}</h3>

<pclass=‘y-writer-only’>{{nickname}}</p>

<pclass=‘y-desc-only bx’>{{short}}</p>

<pclass=‘content-all’>{{content}}</p>

<p class=’y-share-only’><i></i>转发微博</p>

<p class=’y-up-only’ data-artid=’{{id}}’><i></i>{{vote}}</p>

<pclass=“y-zyx”>点爱心赞一下</p>

</div>

<ahref=“javascript:;”class=“mask-close”></a>

<div class=“all-over”></div>

</div>

</script>

为了专题版面的美观,大方块的出现频率应该比小方块更高,所以我使用了一个简单粗暴的方法实现方块的组合,就是使用数组存放每种组合出现的次数来模拟概率。

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

if(arr.length>0){

varmapHash=[1,1,1,1,1,2,2,4];

while(arr.length>0){

varhtml;

varcolNum=returnShortCol();

varindex=18;

if(arr.length<4){index=17;}

if(arr.length<2){index=14;}

varsign=mapHash[Math.floor(Math.random()*index)];

if(sign==1){

vari1=arr.shift();

//具体渲染操作

}elseif(sign==2){

vari1=arr.shift();

vari2=arr.shift();

//具体渲染操作

}else{

vari1=arr.shift();

vari2=arr.shift();

vari3=arr.shift();

vari4=arr.shift();

//具体渲染操作

}

}

}

这段代码写得有点傻,存在着很大的改进空间。其实可以将其封装成函数,通过传参调用来控制每种组合的出现的频率。

关于JS模板引擎的一些阅读:

三、关于跨域的那些事

此次专题页面涉及到三个服务器,分别是单独存放页面HTML的服务器,存放静态资源的CDN服务器,以及存放各种动态数据的后端服务器,所以数据的交互就不能回避跨域这个问题。

数据方块的展示这个好办,jQuery里“一键式”的JSONP便可以实现。这里我是使用了$.getJSON这个方法,在uri query里加上了callback=?就可以实现跨域的AJAX获取。但这里要注意一点,就是后端服务器返回的content-type需要是JSON格式才能使回调函数被正确调用。以前就遇到过返回格式为text/html的坑爹问题。

难点是在大网易通行证的异步登陆和图片上传这两个环节上。要解决这两个问题,都需要用到iframe作为跳板。在解决大网易通行证的异步登陆上,十分感谢@yangjunwei 这篇详细的参考案例——大网易统一登录入口异步登录http://nanny.netease.com/blog/ntes-async-login 。依葫芦画瓢,登录功能便可以实现。

接下来是玩家提交图片的功能。因为涉及到图片的上传,普通的JSONP方法就失效了。普通的JSONP本质上也只是发送一个get请求,而图片的上传是需要通过post方式,而且Content-Type为multipart/form-data才能传送二进制的文件,这个时候就需要iframe来帮忙了。实际上,这与上面提到的异步登录大体上是相同的。先在页面上添加一个宽高都为0,且frameborder也为0的iframe,并将iframe的name赋值,这个iframe用于数据的提交和返回结果的接收。

1

<iframe name=“upload”frameborder=“0″width=“0″height=“0″></iframe>

然后将需要提交的form表单的target指向刚才的iframe,并声明enctype为multipart/form-data,这时候submit就可以通过iframe将表单内容提交到不同域的服务器上。但这样还不够,因为我们需要取得服务器返回的结果,并触发页面上定义好回调的回调函数。这时候需要在iframe上声明

1

document.domain=’163.com’;

使得iframe和父页面拥有相同的domain,然后就可以在iframe中调用父页面的函数,获得服务器返回的结果。

1

2

3

4

5

<script>

document.domain=’163.com’;

varresult={“msg”:“”,“success”:true,“error”:false};

parent.postArtCallback(result);

</script>

关于JS跨域的一些阅读:

四、坑爹的IE大爷

不知道大家会不会觉得浏览器自带的上传控件太丑了,与设计稿的风格格格不入。这时候自然就会想到使用a标签进行模拟。将a标签的click事件和input type=file的change事件进行挂钩,并将input隐藏掉,就能实现这种模拟效果。看上效果很完美,于是心生暗喜。

作为一枚靠谱的前端工程师,接下来肯定要在浏览器端检查一下输入框的字数是否超长,验证码是否填写等等嘛,于是就通过e.preventDefault阻止submit的默认行为,通通先通过JS检查,等验明正身了,才放马交到服务器上。Chrome下一切完美,正准备拍手收工之时,IE突然跳出来大喝一声:“小样!你那代码休想在我身上跑!”这下我愣住了,这IE怎么就那么坑爹了,人家别的浏览器都跑得好好的,就你净捣乱。

于是乎我又得在IE身上折腾一番,终于查明原因。原来IE浏览器下的上传控件input[‘file‘]处于隐藏状态的时候,表单不能通过JS提交,即不能通过form.submit()方法进行提交,这是出于安全原因的考虑。那什么才算隐藏状态?自己分别测试过三种情况,分别为display为none,visibility为hidden,opacity为0的时候都属于隐藏状态,这时候若通过form.submit()的方法进行表单提交都会失败。

看着设计稿上漂亮的样式在苦苦哀求着,我又怎忍心帮它披上默认样式这么挫的外衣呢。于是我只能舍弃客户端的验证,不用JS阻止form submit的默认行为,而是把这项粗重活交由服务端处理了。

除了踩了这个坑,我在IE下使用jQuery方法获取页面DOM元素时也掉进一个阴沟。IE8及其以下的版本,使用$(ele).html()获取到的innerHTML是大写的字符串,而IE9及Chrome等浏览器都是返回小写的字符串。所以要先使用String.toLowrCase进行处理以使得后续的操作前提是一致的。

另外顺带提一下IE下使用new Date()时候传入的参数格式和其他浏览器也是有差别的。通常在Chrome下我们可以使用new Date(‘yyyy-MM-dd’)获得一个时间,但IE下这样的参数格式是无效的,会返回undefined。正确的写法应该是new Date(yyyy,MM,dd),要分别传入三个参数才能返回正确的时间值。

五、关于图片预览和方块定位

在页面上有一个上传图片的环节,用户选择图片后,是需要实现图片预览的功能。那么要实现这个效果,支持HTML5 FileReader的浏览器就可以通过API实现,而IE浏览器则只能通过滤镜的方法实现。这里的IE是指IE9及其以下版本的浏览器,IE10是不能通过滤镜实现这个操作的。多说无益,show me the code,首先是HTML结构。

1

2

3

4

5

6

<div class=“right”>

<div class=“pre-div”><img class=“pre-img”></div>

<pclass=“post-att”>特别提醒:图文并茂的真言将会比没有图片的真言更容易获奖哦!</p>

<aid=“upload-a”>选择图片</a>

<input id=“upload-btn”type=“file”onchange=“handleFiles(this)”name=“picture”>

</div>

为了方便IE下使用滤镜,在img标签外多包了一层div。下面是实现图片预览功能的具体代码。

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

//chrome上传预览

functionhandleFiles(files){

if(window.File&&window.FileReader&&window.FileList&&window.Blob){

//遍历files并处理

files=files.files;

for(vari=0;i<files.length;i++){

varfile=files[i];

varimageType=/image.*/;

//通过type属性进行图片格式过滤

if(!file.type.match(imageType)){

continue;

}

//读入文件

varreader=newFileReader();

reader.onload=function(e){

//e.target.result返回的即是图片的dataURI格式的内容

varimgData=e.target.result,

img=document.createElement(‘img’);

//img.src = imgData;

//展示img

$(“.pre-img”).attr(“src”,imgData).css(“visibility”,“visible”);

}

reader.readAsDataURL(file);

}

}else{//IE

varhtml=“<div class=’pre-img’></div>”;

$(‘.pre-div’).html(”).html(html);

//采用滤镜效果生成图片预览

path=$(‘#upload-btn’).val();

$(‘.pre-img’).css({“filter”:“progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=’true’,sizingMethod=’scale’,src=\””+path+“\”)”});

}

}

其实在折腾这个页面上比较耗时间的反倒是每个方块展开形式的判断。当用户点击方块时候,要判断方块是从顶部展开还是底部展开,当前的屏幕是否足以容纳完全展开的大方块。这里的技术性不强,但是逻辑就比较复杂。首先要判断是否在第一屏展开,第一屏的空间和非第一屏的空间是存在差别的,因为第一屏存在着版头。而要获取点击方块的位置,我们可以借助jQuery的position()方法,获得方块的left值和top值。这里有两点要注意的,就是假如top和bottom的值同时声明,则top指起效,bottom值无效,left值和right值同理。jQuery还有另外一个方法为offset(),与position的区别就是,offset是获取匹配元素在当前视口的相对偏移,而position是获取匹配元素相对父元素的偏移。

关于HTML5 FileReader的一些阅读:

From http://www.g7blogs.com/?p=728

时间: 2024-10-28 21:31:19

藏地传奇真言专题简单小结的相关文章

藏地传奇瀑布流

/** * Created with JetBrains PhpStorm. * User: Gseven * Date: 13-6-17 * Time: 下午4:43 */ var gWaterFall = (function () { var indexNum = 0; //每次刷新最后一条数据的ID var jyNum = 0; //每3次loading加载一个“我要建言” var outBoxHeight = $('.out').height(); //三列外层容器 var outBox

藏地传奇js

http://zd.163.com/m/zhenyan/ js很厉害,有很多值得学习的地方,记录下来. http://res.nie.netease.com/zdcq/qt/13/0625_zhenyan/js/index.js var ZANTEMP; //cookies jQuery.cookie = function(name, value, options) { if (typeof value != 'undefined') { // name and value given, set

软件导论第五周作业-------简单小结

简单小结: 一.JDBC简介 JDBC全称Java Data Base Connectivity(java数据库连接),可以为多种数据库提供统一的访问,是连接Java应用程序和数据库的桥梁,有了JDBC,Java就可以从数据库中读取.存储数据 二.JDBC编程步骤 1.加载驱动程序Class.forName(driverClass); 加载Mysql驱动:Class.forName("com.mysql.jdbc.Driver"); 加载Oracle驱动:Class.forName(&

ASP.NET MVC ViewData/ViewBag 简单小结

近期在项目中遇到一个问题,就是用ViewBag.Model存储匿名对象传递给View,但是需要根据条件给匿名对象添加属性,这个可真心不易,Google了一下发现很多方案都是动态编译神马的,感觉好高大上,最后也没采用,因为不知道动态编译的性能消耗大不大. 最后是自己简单研究了一下,在ViewBag.Model中存储了Dictionary<string, object>,在View通过Model[key]的方式可以正常读取相应的值,在此对ViewData和ViewBag的使用进行一个简单的小结:1

类传奇手游简单Demo

这是一年多前自己闲时以Unity2D制作的很粗糙简单的传奇类手游Demo(单机),已很久未作继续开发. 此小Demo初步完成或实现了如下功能(有诸多考虑欠妥甚至不完善之处): 1).图片资源打包方式.譬如角色,其每套动作以TexturePacker打成一张大图,譬如地图,以自定义的格式将原大图切割成等大小的小图(参见后述的地图编辑器): 2).运行时地图图片资源的按需实时加载与释放: 3).角色动作帧的控制及绘制等: 4).游戏逻辑的处理框架(GameMgr及各种Controller和Handl

Android的Message机制(简单小结)

对于Android的Message机制主要涉及到三个主要的类,分别是Handler.Message.Looper:首先对每个类做一个简单介绍:然后再介绍所谓的Android的Message机制是如何实现的,最后给了一个示例. 一.介绍三个相关的类 1. Handler主要有两个用途:首先是可以定时处理或者分发消息,其次是可以添加一个执行的行为在其它线程中执行, 对于Handler中的方法,可以选择你关心的操作去覆盖它,处理具体的业务操作,常见的就是对消息的处理可以覆盖public voidhan

简单小结几个常见算法的大体实现思想

前言,今天笔试一题,只做了最后一题(输入A,B两字符串,比较是否相等).N年没有笔试了,想起一些还记的算法小结下. PS,想了几种,最后选择先建二叉查找树,再中序查找得有序字符,后循环比较方式. 排序 1.冒泡:从低往上选择临近比较排序: 2.插入:在剩下要排序数据中,选一个按顺序插入: 3.选择:在剩下要排序数据中,选个最值(最大或最小)插入: 4.快速:选择一参照值,从右左两边不断各自向对方移动.与查找值比大小,后交换值: 5.合并:先拆成有序,再比较合并: 6.堆排序:先建堆(上对于下),

WUST暑假集训第一周简单小结

目录 一.dfs序在树状图中的经典应用 二.初探双向广度优先搜索 三.整体二分思想完美解决kth number问题 四.实战模拟退火思想(变步长贪心算法) 五.凸包问题经典例题 六.树的重心问题经典例题 七.矩阵快速幂例题 一.dfs序在树状图中的经典应用 首先是dfs序的问题,什么是dfs序? 我的理解:dfs序也就是将一棵树通过树的遍历顺序将一棵树转化为父节点包含了子节点的序列,n个结点的树对应n个数的序列,一个结点在序列中的表现形式为一段区间,这段区间中包含了该结点的子树区间,且构造的区间

@@Error使用简单小结

使用中经常用到@@Error来判断上一个语句是否执行成功,对此小结一下,可能有些不准确,欢迎指出. 1.1  介绍 SQL SERVER 中@@表示系统全局变量 (1)   返回执行的上一个 Transact-SQL 语句的错误号,如果执行没有错误,则返回 0 . (2)   如果错误是 sys.messages 目录视图中的错误之一,则 @@ERROR 将包含 sys.messages.message_id 列中表示该错误的值.  可以在 sys.messages 中查看与 @@ERROR 错