小博空间不给力,努力载入中..

回到页首回到页尾

利用iframe进行post“跨域”无刷新提交

tinyonly [ HTML5/CSS3 ]

2015.07.10

JSONP应该是目前在请求中使用的最为频繁的跨域方法,但是对于一些,例如文件提交/私密信息(密码提交)等不怎么合适于使用JSONP来进行跨域操作,毕竟JSONP的本质还是属于GET请求。这个时候我们就需要一个可以使用POST的跨域请求。

今天我们要说的就是利用iframe标签进行POST进行“跨域”无刷新提交。先附图。

利用iframe进行post跨域无刷新提交流程图

其实没有真正的使用任何的跨域,只是曲线救国了!通过302的方式重定向到本域,在利用URL的形式进行传输回调的code值来达到最终跨域的目的。

特别提醒:对于form提交到iframe需要在iframe上面设置nameid两个属性,从而来适配到主流的浏览器。


直邮多端适配解决方案浅析

tinyonly [ 重构 ]

2015.04.09

多端适配越来越成为一个产品或者页面的标配,作为运营和消息推送的一个重要的载体-直邮的多端适配一直没有比较好的适配。随着邮箱类的APP的收信份额的进一步提升,我们也尝试着去做一些直邮方面多端适配的方案。

目前主要有方案:

A:定宽缩放大法。这个是目前APP适配直邮最常用的方法

     优点:可以使比较多的直邮可以在缩小的情况下面直接展示

     缺点:由于部分文字或者图片被缩小,导致无法直接查看或者查看起来比较心累,导致运营或者消息推送的质量降低。但可以人为放大缩小

B:URL转移大法。这些一般被用户比较多的私密性推送直邮里面

      优点:可以通过直邮中的链接直接去对应的页面,只要对页面进行比较好的适配,基本完美解决直接缩小的痛点

      缺点:对于一些产品展示类的话比较不友好

C:纯文字的堆积法

      优点:能比较好的适配移动端,不用放大和缩小

      缺点:载体比较单一,基本不符合运营推广,或者多图的消息推送

 

在了解了前人的肩膀后,我们开始了我们的多端适配的方案。主要以C为自己的基准,借鉴了A的部分想法,进行一些图片的适配等。 阅读全文»


从前端代码看无线页面设计

tinyonly [ HTML5/CSS3 ]

2014.03.18

相对于pc的页面,无线的页面开发有其优越性和其弊端。优越性大家都相对比较清楚。更多的可能是去怎么理解和尽可能去解决这些弊端。

 

一. 控制首次的HTTP请求数和加载大小

根据众多的博客的信息和个人经验,首次加载的HTTP请求数不建议超过5个,首次加载的大小不建议大于60KB。

基于上述的两个要求,对于一些小icon我们尽可能用css3去实现,比如简单的箭头,tips的气泡层等等(其他戳这里);当然了,设计同学为了使部分按钮或图形更加形象化和具象化,我们也切图用base64的形式来减少一个或者多个HTTP请求。为了平衡HTTP请求的时间消耗和页面解析base64的解析的时间消耗,建议该图的文件大小小于5KB

 

 

二. 控制图片的大小和数量

或许我们无法控制设计稿子需要哪些设计素材,但是我们可以去控制整体的大小,比如降低整个图片的色域。说到色域,不得不说有几个图片大小的杀手—渐变&阴影&“花哨”的背景图。对于阴影来说,虽然只有一种颜色的渐变,但是正是因为这点大大的加大了整体的图片大小。

当然了,作为一个前端码仔,不能限制设计同学去使用渐变、阴影或者“花哨”的背景。我们希望部分的效果可以呈现出一种规则变化的情景,比如中心扩散或者线性变化等等。这样可以用色域相对比较小的图片和css3的部分属性结合去实现,从而来替代色域值过大的图片

 

 

三.多分辨率适配

设计的稿子一般是640px的宽度,通过换算,它最完美的可以在retina display的320屏幕上显示出来。但是对于多分辨率的移动设备,我们可能需要适配到更多的尺寸屏幕。适配的方案有很多种,其方案一般依靠前端或者设计同学的YY思想。但是限制于各种设计稿的图层布局,真正想要的效果或许比较难去实现。

适当的图层在视觉范围内停止延续或者在有规则的延续都是我们希望看到的。

 

 

除了上述的三点以外,还有很多细节可以优化性能。无线页面的性能优化不仅仅可以依靠代码优化其加载性能和浏览体验,更多需要产品的各个环节来降低各种风险值。


ie6兼容时代已过去,新兼容时代已开启 — 无线重构中反人类兼容问题解决方案

tinyonly [ 重构 ]

2013.10.10

写在前面:

对于刚刚开始学习前端重构知识的同学而言,写一个兼容主流浏览器,特别是兼容ie6的页面会让其觉得是一件非常困难的事情。当然可以从两方面去解决ie6的兼容问题,第一方面是规范自己的代码,其次就是用一些基本且必要的hack来解决部分浏览器的兼容问题,例如最普通的ie6中的双边距问题等等。随着一个人的页面重构和前端开发等技术的积累,再回头去看过去的ie6,也只不过是一块拦路石。当前无线快速发展,ie6的时代已经过去,新的兼容时代已经开始了。ios和android页面适配由于版本,屏幕种类,屏幕大小,调试困难等因素变的尤其的困难。曾几何时是多么羡慕做无线页面重构的同学,不用管ie6等反人类的问题,尽情的使用html5和css3等;但是现在恰恰相反,我们正在无线的各种机子中摸爬滚打,在挖坑填坑中。

================================== 瞎扯分割线 ======================================

自从三月份开始易迅触屏版项目(http://m.51buy.com/)和无线运营正式开始,承担了超过50%的页面重构,近w行的重构代码等。现和大家分享下在项目进行过程中挖坑和填坑过程。

在开始正文前面,说下我们的情况:由于易迅的客户端最低的适配是到android2.1,由于内部有内嵌有webview,所以我们重构的最低适配也是到android2.1。ios的话自然就是ios5以上。


大坑1: position:fixed;

区别于ie6的完全不支持这个属性,目前在android和iphone中还没有发现不支持fixed的手机。fixed的运用可以大大减少在页面滚动的时候js计算量,这个是absolute不可以比拟的。对于性能为上的无线端来说,可以对于表现出一种大爱的态度。但是恰恰因为这种想法,给后期的重构工作中挖了一个又一个坑。其坑具体表现在:

1. 有fixed样式节点的所有子节点中所有的css3会失效或者产生副作用。(具体的机型有android3.0以下的版本的手机)

2. 有fixed样式节点可能会引起击穿效果 (绝大部分手机可能因为代码的问题会引起这个问题)

3. 有fixed样式节点在横竖屏幕切换的时候会保持原来的宽度 (低版本的android机型中会出现这个该问题)

4. 有fixed样式节点中含有input输入框的时候,软键盘可能无法弹出(部分型号的android2.3以下的手机中会出现,webview里面设置不当也会引起这个问题。)

5. 等等

目前发现的比较又针对性的问题又上述的这些,接下来说说解决的方案:(和上面的问题一一对应)

1.  很抱歉,这个问题无法用代码解决,我们只能提醒你在两者中舍弃一个,个人建议你舍弃css3。因为部分css3可以实现的功能点可以用一些图片来替代或者css2.0中的样式来实现。权当降级处理了

2.  在触屏版的设计稿里面有一个全局导航bar(不明真相的同学可以猛戳http://m.51buy.com/),我们采用了fixed的定位方式,在凸出的迅字上面绑了一个点击事件来弹出隐藏的部分。但是在后期测试的时候发现有时候里面出现击穿的效果,即会点中下面的链接,然后无法弹出隐藏部分。最后排查问题发现是由于用translateY来改变其位置引起的,后来采用了top的方式来改变其位置成功解决了这个问题

3.  这个问题很诡异,当我们把fixed改成absolute的时候,发现bug解决了。但是交互和设计以及产品大大们都不同意使用absolute的方式(如果用js来计算位置的话,由于性能问题会引起强烈的抖动,直接否定)。无线旋转屏幕的时候会触发两次的onorientationchange事件,在触发第一次的时候修改其position属性为absolute;在第二次即旋转完毕的时候在换成fixed。

4.  这里的无法弹出软键盘不是指input的focus事件无法触发,而是因为当你的页面中有个fixed节点的属性是height达到一定程度的时候,会在弹出软键盘的时候会被那个节点强行的挤回去,从而造成一个没有弹出软键盘的现象。为了解决这个问题。我们尝试了各种方法,均宣告失败。甚至想到了非常极端布局方法。有兴趣的话可以私聊。如果把fixed替换成absolute的话,不象前几种方案就能解决问题,反而引起了非常不友好的弹窗跳动。最后贡献能相对比较好的解决方案:布局方法和样式如下

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<style>
.mask {display:block;z-index:10;position:fixed;top:50%;margin-top:-100px;left:0;width:100%;color:#222;}
.maskbg{display:block;position:absolute;top:0;left:0;width:100%;height:100%;z-index:0;background-color:rgba(0,0,0,.6);}
.mask .inner {position:absolute;width:100%;top: 0; left: 0;color:#666;z-index:10;}
</style>
<div id="J_wrapper">
	<!-- 此处有页面内容 -->
	<i class="maskbg1"></i>
</div>
<div class="mask">
	<div class="inner">
		<div class="mod_pop" style="display:none;">
			<div class="pop_inner pop_inner2">
				<!-- 弹窗内容,内含input -->
			</div>
		</div>
	</div>
</div>
<script>
        $(".J_maskbg").css("height",$("#J_wrapper").height());
</script>

该布局可以修复两个重大的bug,

  1. 修复上述android2.3机型里面的键盘消失或者窗口跳动的bug
  2. 修复IOS7的safria里面的底部bar消失和顶部地址栏长度减少而引起maskbg高度不够而有出来部分为遮盖的区域

 

大坑2: background-size:contain;

之所以会有这个样式的话是全然为了适应高分辨率的屏幕,比如retina(2*2)的像素点。目前主流的机子都已经到1.5*1.5的像素点。所以淘宝采用了两套图片,一套是480px的,一套是640px。当时在我们采用这个样式的时候,我们发现这个样式并不支持android2.1,取而代之的是需要增加一个hack,-webkit-background-size:**px **px; background-size:**px **px;  这样才完美的解决了这个问题。说明下貌似很多无线的网站没有兼容android2.1。比如我司的腾讯网的触屏版等等。额外需要说明的是-webkit-background-size这个属性并不支持contain。建议采用数字,这样也可以适配到css sprite 图片。

2
3
-webkit-background-size:contain;background-size:contain;         /* 错误,-webkit-background-size没有contain的属性,只支持数字 */
-webkit-background-size:100px 100px;background-size:100px 100px; /* 建议 */

 

大坑3:overflow:scroll

如果有一个页面需要内部滚动,这时候我们自然而言会想到overflow:scroll。这时候我们会告诉你这个属性在无线这里并不支持。幸好的是手机webkit内核提供了一个替代的比较优秀的替代样式:-webkit-overflow-scrolling:touch。他可以完全调用内核中的滚动条空间,这流畅度简直让人无法想象。可惜的是对于低版本的4.0以下的android无法支持到这个属性。这个时候需要外部的js库,例如有iscroll等等。同样要说明的是当你采用了-webkit-overflow-scrolling:touch的时候,无法计算他的scrollTop值,从而限制了lazyload等功能的实现,需要额外的权衡。改实现方式或者改交互方式。

 

大坑4:canvas的部分对象

易迅无线端的9月大促的优惠券发放形式采用的是canvas中的一个属性ctx.globalCompositeOperation = “destination-out”(不明真相的点这里),由于预先有技术调研,知道这个destination-out对于所有的无线浏览器来说都是一致的显示。所以采用这个值的层叠方式可以用来做无线侧的刮刮乐的抽奖产品。但是在后期的自测中发现android设备多次访问该页面后,刮奖的效果莫名的失效。经过排查,发现由于drawImage方法调用在首次访问以后是调用了浏览器中的缓存图片,从而引起刮奖效果的失效。找到了这个问题根本后解决问题的方法也很简单:给drawImage方法调用的图片上面加个随机的时间戳,让每次调用的图片都重新下载,而不是来自浏览器中的缓存图片

诸如上述的反人类的问题还有很多,本次特别挑了上述的几个比较针对性的问题的解决方案和大家分享。其他还有很多问题待下次整理后再与大家分享。现在回过头来看过去的6个月无线重构的经历,可谓是惨不忍睹!可谓是新兼容时代已开始,同志必须加倍努力

/* 文章的最后为大家加点餐后小点 */

/* 小点1 — 在刮刮乐中如何换个角度去获知用户已经知道其中奖信息的情况  */

需求场景: 用户在刮刮乐刮奖过程中知道其中奖信息的时候需要有一个弹窗,该弹窗用来展示具体的中奖信息和部分运营配置的相关促销活                        动入口

技术依赖:canvas / ctx.globalCompositeOperation = “destination-out” / 埋点检测

具体实现:(下图为参考图)

  1. 分析其各种中奖状态的情况,获得一些比较特殊的埋点,测量后得到其相对位置的坐标,组合坐标生成一个数组A(上图中的红点位置就是我取点的位置,仅供参考)
  2. 监听用户刮奖过程中touchmove事件过程中的点B
  3. 由于手指的触碰区域有区别于一般鼠标的大小,一般涉及的区域比较大。针对这个特性,对于点B所在位置进行一个扩充,形成一个区域C,当数组A中的任何一个点在该区域中,需要把数组中的这个点splice。这个数组也称了一个新数组A
  4. 重复123步,直到新数组A的长度到达一定长度时候,触发弹窗事件(我预设这个到达的长度为原先的一半,仅供参考)
12
13
14
15
16
17
18
19
20
21
22
23
/* 代码片段仅供参考 */
/* checkPoints 数组A */
for(var _i = 0, _length = checkPoints.length; _i > _length; _i++ ){
	var point = checkPoints[_i];
	// 区域面判断 
	if(!point || (Math.abs(touchX - point[0]) < lineWidth*1.2 && Math.abs(touchY - point[1]) < lineWidth*1.2)){
		checkPoints.splice(_i,1); // 移除该点
		continue;
	}
}
// 少于原数组一半的时候返回true 
if(checkPoints.length &lt; checkPointsL/2 || checkPoints.length == 0) return true;

/* 小点2 — 无线页面的快速垂直居中和水平居中  */

本方法使用了一点点css3的小技巧,具体的方式的布局和样式如下:

1
2
3
4
5
6
7
8
9
<style>
	.m-wp{position:relative;width:1000px;height:100%;overflow:hidden;}
	.m-bd{position:absolute;top:50%;left:50%;-webkit-transform:translateX(-50%) translateY(-50%)}
</style>
<div class="m-wp"> <!-- 父框最好有个宽度和高度,建议添加overflow -->
	<div class="m-bd">
		这个是想要居中的节点
	</div>
</div>

 


解一套有趣的javascript题

tinyonly [ jQuery/JS ]

2012.10.05

今天偶遇有人在微博上面晒一套javascript题目,国庆看书之余便做了一下:

javascript题目地址:http://www.cnblogs.com/ziyunfei/archive/2012/10/04/2711370.html

—————————————————————————————————————————–

1.TypeError

Function.prototype.toString() 它不是通用的,当调用一个其this值不为函数对象的时候,就会抛出TypeError错误,以下是ecma5里面的原文:

The toString function is not generic; it throws a TypeError exception if its this value is not a Function object. Therefore, it cannot be transferred to other kinds of objects for use as a method.

2.TypeError

new String ( [ value ] ),针对value优先调用目标对象的toString方法,如果结果仍然不是一个原始类型,则再次去调用其valueOf方法,如果返回结果仍然不是一个原始类型则抛出TypeError异常.一下原文:

The [[PrimitiveValue]] internal property of the newly constructed object is set to ToString(value), or to the empty String if value is not supplied.(PrimitiveValue的执行顺序见第三条)

3.String

首先是加法运算,是直接调用ToPrimitive的,而Date类型进行ToPrimitive运算的过程.没有明确指明hint .那么就视为 hint string. 所以优先调用toString,从而得到字符串相加的结果还是字符串,故结果是string,反之如果是减法运算,则为number型。PrimitiveValue的执行顺序如下:

1. Let v be ToPrimitive(value).
2. If Type(v) is String, then
a. Parse v as a date, in exactly the same manner as for the parse method (15.9.4.2); let V be the time value for this date.
3. Else, let V be ToNumber(v).
4. Set the [[PrimitiveValue]] internal property of the newly constructed object to TimeClip(V) and return

4.undefined

什么是void,void是一个操作符,该操作符指定要计算一个表达式但是不返回值。void(expression)与void expression一致,本题其实也就是对null的typeof,即为undefined

5.[object Object]

new F();是对类的实例化,按照执行过程,他既不是undefined和null,所以直接toObject,得到参数的类型class为object,最后返回”[object “, class, “]”这三个的串联字符串,即[object Object]。以下ecma5的原文:

1. If the this value is undefined, return “[object Undefined]”.
2. If the this value is null, return “[object Null]”.
3. Let O be the result of calling ToObject passing the this value as the argument.
4. Let class be the value of the [[Class]] internal property of O.
5. Return the String value that is the result of concatenating the three Strings “[object “, class, and “]”.

6.RangeError

一个数组最多可以包含4 294 967 295个项,即32位,超过32的时候(题目中为33位),会那用ToUint32来和数组长度来判断,如果两者不相等,则报RangeError错误以下ecma5原文:

If the argument len is a Number and ToUint32(len) is equal to len, then the length property of the newly constructed object is set to ToUint32(len). If the argument len is a Number and ToUint32(len) is not equal to len, a RangeError exception is thrown.

7.false

2的33远远木有infinity的地步,所以还是在正常数字,但是已经出位(超过32位),但是对于(D | D)这个位或的计算方法,具体的计算方法如下:

Math.pow(2, 33) = 1000 0000 0000 0000 0000 0000 0000 0000 0000
Math.pow(2, 33) = 1000 0000 0000 0000 0000 0000 0000 0000 0000
———————————————————————————————————————
OR              = 0000 0000 0000 0000 0000 0000 0000 0000 0000

由上式得出,D | D = 0; 0 == D  ==>false

8. 

这题完全是正则的,$’ 替换为匹配位之后的子串,所以输出两个重复的合在一起的字符串

9. function

在浏览器的解析器中,在执行环境中加载的数据时,对函数声明和函数表达式并非一致,解析器会率先读取函数声明,并使其在执行任何代码之前可用;至于函数表达式,则必须等到解析器执行到他所在的代码行时,才会真正被解释执行,故

eval(‘typeof F; function F() {}’);

可以理解成为

eval(‘ function F() {}typeof F;’);

这样就比较好理解了,所以F为function。

留下小问题几枚:

eval(‘typeof F;var F = function(){}’);

eval(‘alert(f(1,1));var f = function(a,b){return a+b}’);

答案是:SyntaxError: Unexpected token ILLEGAL;原因如下:函数位于一个初始化的语句中,而不是一个函数的声明,换句话也就是说在一个执行到函数所在的语句以前,变量f中不会保存对函数的引用,而且第一句会产生错误,也不会执行到下一句

答案可以用firebug看 – -!

10.暂无

仅从标准角度来看.答案应该是,确认抛异常,而不是可能抛异常。但是部分浏览器貌似解释又不同,以下ecma5的文档解释,大家可以各自看看,说说自己的看法:

The production DebuggerStatement : debugger ; is evaluated as follows:
1. If an implementation defined debugging facility is available and enabled, then
a. Perform an implementation defined debugging action.
b. Let result be an implementation defined Completion value.
2. Else
a. Let result be (normal, empty, empty).
3. Return result.