iLeichun

当前位置:首页

解决input标签与图片按钮水平对齐问题

分类:CSS  来源:网络  时间:Apr 11, 2012 9:20:12 PM

在页面设计的时候,很容易就碰到 input 标签与图片按钮、与<A>标签或 button 按钮与<A>标签等之间水平对齐的问题,记录一下,不再费口舌了!

这里以一个“登录-注册”按钮的例子来说明一下,Html代码及相关CSS样式:

<style type="text/css">
.btn input { padding:0px; border:none; }
.btn2 { vertical-align:middle; background:url(login-btn.gif) #ffffff; color: #FE6591; display: inline-block; font: 700 14px "microsoft yahei"; cursor: pointer; text-align:center; height: 30px; line-height: 30px; width: 80px; padding:0px; }
</style>
<li class="btn"><input type="submit" class="btn2" value="登 录" name="login" id="login"> <a href="register.php" class="btn2" id="reg">注 册</a></li>

从上面的CSS可以看出,解决方法其实很简单,只要加上 vertical-align:middle 属性就可以了。

其它样式可以自己体会!!

也可以用以下CSS来测试, vertical-align:middle 还是不能少,只是换作了无图按钮!

<style type="text/css">
.btn input { padding:0px; height:32px; }
.btn2 { background:#ffffff; border:1px solid #0DC7E2; border-radius: 4px 4px 4px 4px; box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.15); color: #FE6591; display: inline-block; font: 700 14px "microsoft yahei"; cursor: pointer; text-align:center; vertical-align:middle; width:100px; height:30px; line-height:30px; }
</style>

来源:http://www.nuodou.com/a/765.html

理解Javascript的闭包

分类:JavaScript  来源:网络  时间:Apr 11, 2012 9:18:13 PM

Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包对于那些使用传统静态语言C/C++的程序员来说是一个新的语言特性。本文将以例子入手来介绍Javascript闭包的语言特性,并结合一点ECMAScript语言规范来使读者可以更深入的理解闭包。

注:本文是入门文章,例子素材整理于网络,如果你是高手,欢迎针对文章提出技术性建议和意见。本文讨论的是Javascript,不想做语言对比,如果您对Javascript天生不适,请自行绕道。

什么是闭包

闭包是什么?闭包是Closure,这是静态语言所不具有的一个新特性。但是闭包也不是什么复杂到不可理解的东西,简而言之,闭包就是:

  • 闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。
  • 闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配
  • 当在一个函数内定义另外一个函数就会产生闭包

上面的第二定义是第一个补充说明,抽取第一个定义的主谓宾——闭包是函数的‘局部变量’集合。只是这个局部变量是可以在函数返回后被访问。(这个不是官方定义,但是这个定义应该更有利于你理解闭包)

做为局部变量都可以被函数内的代码访问,这个和静态语言是没有差别。闭包的差别在于局部变变量可以在函数执行结束后仍然被函数外的代码访问。这意味着函数必须返回一个指向闭包的“引用”,或将这个”引用”赋值给某个外部变量,才能保证闭包中局部变量被外部代码访问。当然包含这个引用的实体应该是一个对象,因为在Javascript中除了基本类型剩下的就都是对象了。可惜的是,ECMAScript并没有提供相关的成员和方法来访问闭包中的局部变量。但是在ECMAScript中,函数对象中定义的内部函数(inner function)是可以直接访问外部函数的局部变量,通过这种机制,我们就可以以如下的方式完成对闭包的访问了。

 

function greeting(name) {
    var text = ¹Hello ¹ + name; // local variable
    // 每次调用时,产生闭包,并返回内部函数对象给调用者
    return function() { alert(text); }
}
var sayHello=greeting("Closure");
sayHello()  // 通过闭包访问到了局部变量text

上述代码的执行结果是:Hello Closure,因为sayHello()函数在greeting函数执行完毕后,仍然可以访问到了定义在其之内的局部变量text。

好了,这个就是传说中闭包的效果,闭包在Javascript中有多种应用场景和模式,比如Singleton,Power Constructor等这些Javascript模式都离不开对闭包的使用。

ECMAScript闭包模型

ECMAScript到底是如何实现闭包的呢?想深入了解的亲们可以获取ECMAScript 规范进行研究,我这里也只做一个简单的讲解,内容也是来自于网络。

在ECMAscript的脚本的函数运行时,每个函数关联都有一个执行上下文场景(Execution Context) ,这个执行上下文场景中包含三个部分

  • 文法环境(The LexicalEnvironment)
  • 变量环境(The VariableEnvironment)
  • this绑定

其中第三点this绑定与闭包无关,不在本文中讨论。文法环境中用于解析函数执行过程使用到的变量标识符。我们可以将文法环境想象成一个对象,该对象包含了两个重要组件,环境记录(Enviroment Recode),和外部引用(指针)。环境记录包含包含了函数内部声明的局部变量和参数变量,外部引用指向了外部函数对象的上下文执行场景。全局的上下文场景中此引用值为NULL。这样的数据结构就构成了一个单向的链表,每个引用都指向外层的上下文场景。

例如上面我们例子的闭包模型应该是这样,sayHello函数在最下层,上层是函数greeting,最外层是全局场景。如下图:

因此当sayHello被调用的时候,sayHello会通过上下文场景找到局部变量text的值,因此在屏幕的对话框中显示出”Hello Closure”
变量环境(The VariableEnvironment)和文法环境的作用基本相似,具体的区别请参看ECMAScript的规范文档。

闭包的样列

前面的我大致了解了Javascript闭包是什么,闭包在Javascript是怎么实现的。下面我们通过针对一些例子来帮助大家更加深入的理解闭包,下面共有5个样例,例子来自于JavaScript Closures For Dummies(镜像)。
例子1:闭包中局部变量是引用而非拷贝

function say667() {
    // Local variable that ends up within closure
    var num = 666;
    var sayAlert = function() { alert(num); }
    num++;
    return sayAlert;
}

var sayAlert = say667();
sayAlert()

因此执行结果应该弹出的667而非666。

例子2:多个函数绑定同一个闭包,因为他们定义在同一个函数内。

function setupSomeGlobals() {
    // Local variable that ends up within closure
    var num = 666;
    // Store some references to functions as global variables
    gAlertNumber = function() { alert(num); }
    gIncreaseNumber = function() { num++; }
    gSetNumber = function(x) { num = x; }
}
setupSomeGlobals(); // 为三个全局变量赋值
gAlertNumber(); //666
gIncreaseNumber();
gAlertNumber(); // 667
gSetNumber(12);//
gAlertNumber();//12

例子3:当在一个循环中赋值函数时,这些函数将绑定同样的闭包

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        var item = ¹item¹ + list[i];
        result.push( function() {alert(item + ¹ ¹ + list[i])} );
    }
    return result;
}

function testList() {
    var fnlist = buildList([1,2,3]);
    // using j only to help prevent confusion - could use i
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

testList的执行结果是弹出item3 undefined窗口三次,因为这三个函数绑定了同一个闭包,而且item的值为最后计算的结果,但是当i跳出循环时i值为4,所以list[4]的结果为undefined.

例子4:外部函数所有局部变量都在闭包内,即使这个变量声明在内部函数定义之后。

function sayAlice() {
    var sayAlert = function() { alert(alice); }
    // Local variable that ends up within closure
    var alice = ¹Hello Alice¹;
    return sayAlert;
}
var helloAlice=sayAlice();
helloAlice();

执行结果是弹出”Hello Alice”的窗口。即使局部变量声明在函数sayAlert之后,局部变量仍然可以被访问到。

例子5:每次函数调用的时候创建一个新的闭包

function newClosure(someNum, someRef) {
    // Local variables that end up within closure
    var num = someNum;
    var anArray = [1,2,3];
    var ref = someRef;
    return function(x) {
        num += x;
        anArray.push(num);
        alert(¹num: ¹ + num +
        ¹
anArray ¹ + anArray.toString() +
        ¹
ref.someVar ¹ + ref.someVar);
    }
}
closure1=newClosure(40,{someVar:¹closure 1¹});
closure2=newClosure(1000,{someVar:¹closure 2¹});

closure1(5); // num:45 anArray[1,2,3,45] ref:¹someVar closure1¹
closure2(-10);// num:990 anArray[1,2,3,990] ref:¹someVar closure2¹

闭包的应用

Singleton 单件:

var singleton = function () {
    var privateVariable;
    function privateFunction(x) {
        ...privateVariable...
    }

    return {
        firstMethod: function (a, b) {
            ...privateVariable...
        },
        secondMethod: function (c) {
            ...privateFunction()...
        }
    };
}();

这个单件通过闭包来实现。通过闭包完成了私有的成员和方法的封装。匿名主函数返回一个对象。对象包含了两个方法,方法1可以方法私有变量,方法2访问内部私有函数。需要注意的地方是匿名主函数结束的地方的’()’,如果没有这个’()’就不能产生单件。因为匿名函数只能返回了唯一的对象,而且不能被其他地方调用。这个就是利用闭包产生单件的方法。

 

来源:http://coolshell.cn/articles/6731.html

CSS3 icon font完全指南

分类:CSS  来源:网络  时间:Apr 11, 2012 9:16:43 PM

大家都知道现在各个浏览器都支持CSS3的自定义字体(@font-face),包括IE6都支持,只是各自对字体文件格式的支持不太一样。那么对于网站中用到的各种icon,我们就可以尝试使用font来实现,本文将详细讲解这种用法。

为什么要将icon做成字体?

在很多网站项目中,我们常常会用到各种透明小图标,然后网站要兼容各个浏览器,也可能会有多个尺寸,甚至还要考虑换肤等需求。那么我们就要将这些小图标输出为多种尺寸、颜色和文件格式,比如png8 alpha透明或者png8 index透明等。

比如,twitter用到的各种小icon:

这种情况下,使用字体来实现图标就有很多优势:

  • 字体文件小,一般20-50kb;
  • 容易编辑和维护,尺寸和颜色可以用css来控制;
  • 透明完全兼容IE6;

如何将icon变成字体?

最关键的是要将设计稿中的icon(要有矢量路径,位图没法转化)完美还原成字体,这并不是很麻烦。

我们要用到一些字体编辑软件,比如FontCreator、FontLab等,这里我们用FontLab来演示。

还原步骤很简单:

PSD–>eps–>FontLab,即将PSD转换为illustrator的eps格式,然后将某个字符复制到FontLab中即可。

具体步骤:

打开设计稿psd,将其保存为Photoshop eps格式,我们这里以Qzone中说说发表框的表情icon为例:

在illustrator中打开保存的eps文件:

取消分组,然后点选某个icon,复制。

打开FontLab,随便打开一款字体文件,比如tahoma.ttf:

然后双击某个字符,将原有图形删除,粘贴刚才复制的icon对象:

调整图形大小,一个icon就完成还原了。

就是这么简单。所有icon还原完之后,生成字体文件就可以了。

查看字体对应字符,可以在字体列表中,在某个字体上右键查看属性(快捷键Alt+Enter),查看该字体对应的字符:

可以看到字体对应的字符是i,unicode编码是0069。

字体格式的浏览器支持:

目前,各个浏览器对字体格式的支持是最大的区别:

  • webkit/safari:支持TrueType/OpenType(.ttf),OpenType PS(.otf),iOS4.2+支持.ttf,iOS 4.2以下只支持SVG字体;
  • Chrome:除webkit支持的以外,从Chrome 6开始,开始支持woff格式;
  • Firefox:支持.ttf和.otf,从Firefox 3.6开始支持woff格式;
  • Opera:支持.ttf、.otf、.svg。尚不支持woff;
  • IE:只支持eot格式,IE9开始支持woff。

注:以上资料来自于:webfonts.info

注:woff是最新的web开放字体格式(web open font format),w3c推荐,主要优势是针对浏览器进行优化,字体文件小。详情可查看wiki:

在CSS中使用icon字体:

先使用font-face声明字体:

 

1
2
3
4
5
6
7
8
@font-face {
    font-family: ¹emotion¹;
    src: url(¹emotion.eot¹); /* IE9*/
    src: url(¹emotion.eot?#iefix¹) format(¹embedded-opentype¹), /* IE6-IE8 */
         url(¹emotion.woff¹) format(¹woff¹), /* chrome、firefox */
         url(¹emotion.ttf¹)  format(¹truetype¹), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
         url(¹emotion.svg#svgFontName¹) format(¹svg¹); /*  iOS 4.1- */
    }

 

然后,在icon元素上使用该字体就好了:

 

1
2
3
.icon{font-family:"emotion" Tahoma;
...
}

 

最后,在页面中使用这个字体:

<span class="icon">i</span>

支持CSS3的浏览器可以更上流一点儿,我们每次修改html可能没那么方便,如果要改变某个icon,则可能需要修改相关字符,比如将i修改为e等。如果使用css3的伪元素,可以方便很多:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.icon{
display:inline-block;
width:16px;
height:16px;/*占个位**/
...
}
.icon:after,.icon::after{
font-family:"emotion" Tahoma;
display:inline-block;
content:"i";/*在这里调用字符*/
width:16px;
height:16px;
margin-left:-16px;/*position:absolute什么的也可以,看具体情况*/
}

 

嗯,就是用实际元素占位,用伪元素+content属性显示icon,然后覆盖到实际元素上面,之后我们修改某个icon只需要更改css样式就可以了。

IE依然棘手:

因为IE9以前只支持eot格式,所以需要将ttf转换为eot先,这里可以使用微软官方的WEFT软件,也可以使用一些在线工具:

  • http://www.kirsle.net/wizards/ttf2eot.cgi 在线转ttf为eot格式;
  • http://www.fontsquirrel.com/fontface/generator强大的在线转ttf为eot、woff等字体格式

另外,eot文件必须添加域名白名单才可以使用,这里推荐使用CreateMyEOT:

总结:

其实,这种方法有一个不足,就是只支持纯色icon,最多能高端浏览器上实现渐变色或图形蒙板。

当然,我们有很多场景是用纯色icon,特别是在Windows 8这种Metro UI开始越来越多的时候。

另外,这种方法可以有效减少页面的请求,但是对于习惯使用CSSGaGa的auto sprite功能的同学来说,这种方法对页面性能的提升不大。

但是对于移动终端,特别是webapp中,这种方法还是有很大的用武之地的,可以很方便的兼容多分辨率,配合离线存储效果更佳。

如果你有这方面更好的建议和意见,欢迎提出。

 

来源:http://www.qianduan.net/css3-icon-font-guide.html

现在就开始使用HTML5的十大原因

分类:HTML  来源:网络  时间:Apr 11, 2012 9:15:28 PM

你难道还没有考虑使用HTML5? 当然我猜想你可能有自己的原因;它现在还没有被广泛的支持,在IE中不好使,或者你就是喜欢写比较严格的XHTML代码。HTML5是web开发世界的一 次重大的改变,事实上不管你是否喜欢,它都是代表着未来趋势。其实HTML5并不难理解和使用。我们这里能列出许多原因为什么现在要开始使用HTML5。

目前有很多的文章介绍使用HTML5并且介绍了使用它的优势和好处,没错,我们这篇文章也类似。随着更多这样的文章,以及Apple的支持, Adobe围绕HTML5的产品开发,以及移动flash的死亡,如此多网站的支持,我想对那些仍旧没有或者不想接受它的人说一些话。我认为主要得原因是,它看起来像一个神秘的东西。很多感觉它像喷气背包或者飞行汽车。一个未经验证的非凡想法但是并不实际。但是事实上现在已近非常的实际了。

为了解密HTML5并且帮助顽固的开发设计人员,我这里写了列出了使用HTML5的几大原因,希望对大家有帮助!

第十大原因:易用性

俩个原因使得使用HTML5创建网站更加简单:语义上及其ARIA。新的HTML标签像<header>, <footer>,<nav>,<section>, <aside>等等,使得阅读者更加容易去访问内容。在以前,即使你定义了class或者ID你的阅读者也没有办法去了解给出的一个div究 竟是什么。使用新的语义学的定义标签,你可以更好的了解HTML文档,并且创建一个更好的使用体验。

ARIA是一个W3C的标准主要用来对HTML文章中的元素指定“角色“,通过角色属性来创建重要的页面地形例 如,header,footer,navigation或者aritcle很有必要。这一点曾经被忽略掉了并且没有被广泛使用,因为事实上并不验证。然 而,HTML5将会验证这样属性。同时,HTML5将会内建这些角色并且无法不覆盖。更多的HTML5和ARIA讨论,请大家查看这里。

第九大原因:视频和音频支持

忘了flash和其它第三方应用吧,让你的视频和音频通过HTML5标签<video>和<audio>来访问资源。正确 播放媒体一直都是一个非常可怕的事情,你需要使用<embed>和<object>标签,并且为了它们能正确播放必须赋予一大堆 的参数。你的媒体标签将会非常复杂,大堆得令人迷惑的代码。而且HTML5视频和音频标签基本将他们视为图片:<video src=””/>。但是其它参数例如宽度和高度或者自动播放呢?不必担心,只需要像其它HTML标签一样定义:<video src=”url” width=”640px” height=”380px” autoplay/>。

实际上这个过程非常简单,然而我们的老浏览器可能并不喜欢我们的HTML5,你需要添加更多代码来让他们正确工作。但是这个代码还是比<embed>和<object>来的简单的多。

第八大原因:Doctype

没错,就是doctype,没有更多内容了。是不是非常简答?不需要拷贝粘贴一堆无法理解的代码,也没有多余的head标签。最大的好消息在于,除了简单,它能在每一个浏览器中正常工作即使是名声狼藉的IE6。

第七大原因:更清晰的代码

如果你对于简答,优雅,容易阅读的代码有所偏好的话,HTML5绝对是一个为你量身定做的东西。HTML5允许你写出简单清晰富于描述的代码。符合语义学的代码允许你分开样式和内容。看看这个典型的简单拥有导航的heaer代码:
<div id=”header”>  <h1>Header Text</h1>  <div id=”nav”>   <ul>    <li><a href=”#”>Link</a></li>    <li><a href=”#”>Link</a></li>    <li><a href=”#”>Link</a></li>   </ul>  </div> </div>
是不是很简单?但是使用HTML5后会使得代码更加简单并且富有含义:
<header>  <h1>Header Text</h1>  <nav>   <ul>    <li><a href=”#”>Link</a></li>    <li><a href=”#”>Link</a></li>    <li><a href=”#”>Link</a></li>   </ul>  </nav> </header>
使用HTML5你可以通过使用语义学的HTML header标签描述内容来最后解决你的div及其class定义问题。 以前你需要大量的使用div来定义每一个页面内容区域,但是使用新 的<section>,<article>,<header>,<footer>,<aside> 和<nav>标签,需要你让你的代码更加清晰易于阅读。

第六大原因:更聪明的存储

HTML5中最酷的特性就是本地存储。有一点像比较老的技术cookie和客户端数据库的融合。它比cooke更好用因为支持多个windows存储,它拥有更好的安全和性能,即使浏览器关闭后也可以保存。

因为它是个客户端的数据库,你不用担心用户删除任何cookie,并且所有主流浏览器都支持。

本地存储对于很多情况来说都不错, 它是HTML5工具中一个不需要第三方插件实现的。能够保存数据到用户的浏览器中意味你可以简单的创建一些应用特性例如:保存用户信息,缓存数据,加载用户上一次的应用状态。

第五大原因:更好的互动

我们都喜欢更好的互动,我们都喜欢对于用户有反馈的动态网站,用户可以享受互动的过程。输入<canvas>,HTML5的画图标签允许你做更多的互动和动画,就像我们使用Flash达到的效果。

除了<canvas>,HTML5同样也拥有很多API允许你创建更加好的用户体验并且更加动态的web应用程序。 这里有一个列表:

  • Drag and Drop (DnD)
  • Offline storage database
  • Browser history management
  • document editing
  • Timed media playback

    第四大原因:游戏开发

    没错, 你可以使用HTML5的<canvas>开发游戏。HTML5提供了一个非常伟大的,移动友好的方式去开发有趣互动的游戏。如果你开发Flash游戏,你就会喜欢上HTML5的游戏开发。

    Script-tutorials目前提供了4个不部分的HTML5游戏开发教程,这里看看他们开发的有趣游戏:

  • HTML5 Gaming Development Lesson One
  • HTML5 Gaming Development Lesson Two
  • HTML5 Gaming Development Lesson Three
  • HTML5 Gaming Development Lesson Four

    第三大原因: 遗留及其跨浏览器支持
    你的现代流行浏览器都支持HTML5(Chrome,Firefox,Safari,IE9和Opera),并且创建了HTML5 doctype这样所有的浏览器,即使非常老非常令人厌恶浏览器像IE6都可以使用。但是因为老的浏览器能够识别doctype并不意味它可以处理 HTML5标签和功能。幸运的是,HTML5已经使得开发更加简单了,更多支持更多浏览器,这样老的IE浏览器可以通过添加javascript代码来使 用新的元素:
    <!–[if lt IE 9]>  <script src=”http://html5shiv.googlecode.com/svn/trunk/html5.js”></script> <![endif]–>

    第二大原因: 移动,移动还是移动

    你可以称之为“直觉”,但是我认为移动技术将会变得更加的流行。我知道,这里有些非常疯狂的猜测,有些可能你也想到了 – Mobile是一个时尚!移动设备将占领世界。更多的接受移动设备将会增长的非常迅速。这意味着更多的用户会选择使用移动设备访问网站或者web应用。 HTML5是最移动化的开发工具。随着Adobe宣布放弃移动flash开发,你将会考虑使用HTML5来开发webp应用。

    当手机浏览器完全支持HTML5那么开发移动项目将会和设计更小的触摸显示一样简单。这里有很多的meta标签允许你优化移动:

  • viewport: 允许你定义viewport宽度和缩放设置;
  • 全屏浏览器: ISO指定的数值允许Apple设备全屏模式显示;
  • Home screen icons:  就像桌面收藏,这些图标可以用来添加收藏到IOS和Android移动设备的首页。

    第一大原因: 它是未来,开始用吧!

    最大的原因今天你就开始使用HTML5是因为它是未来,不要掉队了!HTML5不会往每个方向发展,但是更多的元素已经被很多公司采用,并且开始着 手开发。HTML5其实更像HTML,它不是一个新的技术需要你重新学习!如果你开发XHTML strict的话你现在就已经在开发HTML5了。为什么不更完整的享受HTML5的功能呢?

    你实际上没有任何借口不接受HTML5。事实上我唯一一个原因使用HTML5是因为它书写代码简单清晰。其它的特性其实我也没有真正使用。你可以考 虑现在开始使用HTML5书写代码,它能帮助你改变书写代码的方式及其设计方式。开始用HTML5代码编写web应用吧,说不定下一个移动应用或者游戏应 用就是用HTML5开发的!

硅谷称之为“常识”的网站设计过程原则

分类:网站建设  来源:网络  时间:Apr 11, 2012 9:13:42 PM

初级创业者应该搞清楚保持细致与步入主流的区别。以下是网站设计过程中的几个原则,硅谷的人也常不屑地称其为“常识(Normals)”。

怎样介绍网站

不用告诉用户你网站的“原理(how it works)”或“是什么(what it is)”,当然也无需告诉他们你的公司有多奇妙。你需要抓住重点,完整而明确地告诉用户你提供什么样的服务。新用户需要知道的是,你提供的服务在他们的生活中能起到什么作用。

看一下Twitter主页是怎么向新用户介绍的。很简洁,“欢迎来到 Twitter。与你关心的人们一起,探寻变化的大千世界”。Facebook也类似,“联结你我,分享生活,尽在Facebook”。非常有才!现在初级创业者应该知道,采用明确的方式告诉用户什么时候使用、为什么有用。比如通过前面两句话我们就能知道,Twitter是用来探寻世界的变化,Facebook则是用来沟通和分享。

确定呈现内容

我们知道你可能会这样想:“Facebook与Twitter当然能用时髦语句来介绍自己,因为新用户在去他们的网站前,就已经知道他们的网站是做什么的”。没错,这也是问题的关键。现在的大部分人都是从他人那里听说某个网站,而你的工作就是满足这些人对你网站的期望,服务当然也是越快速、越令人信服越好。

怎样才能让新用户爱上你的网站? 这就需要给他们带来一段难忘的初始体验。建立一个引导式的过程,让他们感觉像是在进行愉快的散步,这样用户就会很高兴地了解当前服务能为他们做些什么。

太多的网站在新用户注册后便甩手不管,期望他们自己去摸索和发现下一步该做什么。相反,应该把新用户看成正与你的网站约会,接着通过一个优雅、直观、使人愉悦的引导过程,让他们了解网站的操作流程。对初级创业者来说,学会开始、驾驭并让使用体验个性化都是极其重要的。初级创业者应该正确对待错误,不应害怕冒险或固化行动 ,措施应该灵活且可以在必要时撤消。

例如,Twitter在引导用户使用这个服务的同时,也会询问他们的兴趣,然后立即利用这些信息为其创造个性化体验。完成这一过程后,无关的应用将被关闭,这样用户的面板上就只会显示那些自己可能感兴趣的功能选项。

独立而不孤立

许多网站还未赢得用户信任,就在用户登陆时要求获得他们的Facebook授权。这种做法可能会让新、老用户都产生疏远感。很多新用户的朋友也是网络新手,所以他们在网络中的沟通可能还并不多。另一些人则希望在Facebook之外的网站与他人建立沟通关系;或是更希望在没有Facebook的地方获得一丝“喘息”。

另一方面,他们也不想让朋友知道自己正使用Faceboo帐号登陆第三方网站。在越来越多的垃圾信息威胁到自己朋友时,他们也对第三方网站授权变得越来越谨慎。在这种情况下,如果网站强制要求用户创建帐号,或在他们确认自己需要这个服务之前,让其使用Facebook帐户登陆,失去这些用户的风险将比获得的好处更大。

这并不是说不应该给用户提供使用Facebook登陆的选项,只是建议先让他们爱上你的网站。对一个还未注册的用户来说,他即使没有朋友使用你的网站,网站对他也应该是有价值和吸引人的。例如,Pinterest允许未注册用户自由地浏览内容。用户只有在决定加入的时候,才会尝试使用Facebook帐户登陆。新用户加入后,不管有没有朋友在使用这个服务,他们都能立即开始发布内容、表达喜爱、发表评论等。

化繁为简

针对特定用户进行产品设计的关键是满足他们的特别需求。即使你的目标用户不是网络新人,当没有经验的游客来访问你的网站时,也要确保他们能有收获。直观的界面能让每个用户都喜欢,还要能够预测用户的下一步操作。让产品步入主流,它必须要简单,还能满足用户需求。用户往往不关心你的技术能做什么,而只关心你的服务能帮他们完成什么。

还有大量尚开发的机遇等着那些能化繁为简的企业家去开发。如果不知是什么,或许你的爷爷奶奶也能给你带来启发。

jQuery代码优化:事件委托篇

分类:JQuery  来源:网络  时间:Apr 11, 2012 9:12:34 PM

随着DOM结构的复杂化和Ajax等动态脚本技术的运用,事件委托自然浮出了水面。jQuery为绑定和委托事件提供了.bind()、.live()和.delegate()方法。本文在讨论这几个方法内部实现的基础上,展示它们的优劣势及适用场合。

事件委托

事件委托的事例在现实当中比比皆是。比如,有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。

我们知道,DOM在为页面中的每个元素分派事件时,相应的元素一般都在事件冒泡阶段处理事件。在类似 body > div > a 这样的结构中,如果单击a元素,click事件会从a一直冒泡到div和body(即document对象)。因此,发生在a上面的单击事件,div和body元素同样可以处理。而利用事件传播(这里是冒泡)这个机制,就可以实现事件委托。具体来说,事件委托就是事件目标自身不处理事件,而是把处理任务委托给其父元素或者祖先元素,甚至根元素(document)。

.bind()

假设有一个多行多列的表格,我们想让用户单击每个单元格都能看到与其中内容相关的更多信息(比如,通过提示条)。为此,可以为每个单元格都绑定click事件:

$("info_table td").bind("click", function(){/*显示更多信息*/});

问题是,如果表格中要绑定单击事件的有10列500行,那么查找和遍历5000个单元格会导致脚本执行速度明显变慢,而保存5000个td元素和相应的事件处理程序也会占用大量内存(类似于让每个人亲自站在门口等快递)。

在前面这个例子的基础上,如果我们想实现一个简单的相册应用,每页只显示50张照片的缩略图(50个单元格),用户点击“第x页”(或“下一页”)链接可以通过Ajax从服务器动态加载另外50张照片。在这种情况下,似乎使用.bind()方法为50个单元格绑定事件又可以接受了。

事实却不然。使用.bind()方法只会给第一页中的50个单元格绑定单击事件,动态加载的后续页面中的单元格都不会有这个单击事件。换句话说,.bind()只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件(类似于新来的员工收不到快递)。

事件委托可以解决上述两个问题。具体到代码上,只要用jQuery 1.3新增的.live()方法代替.bind()方法即可:

$("#info_table td").live("click",function(){/*显示更多信息*/});

这里的.live()方法会把click事件绑定到$(document)对象(但这一点从代码中体现不出来,这也是.live()方法饱受诟病的一个重要原因,稍后再详细讨论),而且只需要给$(document)绑定一次(不是50次,更不是5000次),然后就能够处理后续动态加载的照片单元格的单击事件。在接收到任何事件时,$(document)对象都会检查事件类型和事件目标,如果是click事件且事件目标是td,那么就执行委托给它的处理程序。

.live()

到目前为止,一切似乎很完美。可惜,事实并非如此。因为.live()方法并不完美,它有如下几个主要缺点:

  • $()函数会找到当前页面中的所有td元素并创建jQuery对象,但在确认事件目标时却不用这个td元素集合,而是使用选择符表达式与event.target或其祖先元素进行比较,因而生成这个jQuery对象会造成不必要的开销;
  • 默认把事件绑定到$(document)元素,如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失;
  • 只能放在直接选择的元素后面,不能在连缀的DOM遍历方法后面使用,即$("#infotable td").live...可以,但$("#infotable").find("td").live...不行;
  • 收集td元素并创建jQuery对象,但实际操作的却是$(document)对象,令人费解。

解决之道

为了避免生成不必要的jQuery对象,可以使用一种叫做“早委托”的hack,即在$(document).ready()方法外部调用.live():

(function($){
    $("#info_table td").live("click",function(){/*显示更多信息*/});})(jQuery);

在此,(function($){...})(jQuery)是一个“立即执行的匿名函数”,构成了一个闭包,可以防止命名冲突。在匿名函数内部,$参数引用jQuery对象。这个匿名函数不会等到DOM就绪就会执行。注意,使用这个hack时,脚本必须是在页面的head元素中链接和(或)执行的。之所以选择这个时机,因为这时候刚好document元素可用,而整个DOM还远未生成;如果把脚本放在结束的body标签前面,就没有意义了,因为那时候DOM已经完全可用了。

为了避免事件冒泡造成的性能损失,jQuery从1.4开始支持在使用.live()方法时配合使用一个上下文参数:

$("td",$("#info_table")[0]).live("click",function(){/*显示更多信息*/});

这样,“受托方”就从默认的$(document)变成了$("#infotable")[0],节省了冒泡的旅程。不过,与.live()共同使用的上下文参数必须是一个单独的DOM元素,所以这里指定上下文对象时使用的是$("#infotable")[0],即使用数组的索引操作符来取得的一个DOM元素。

.delegate()

如前所述,为了突破单一.bind()方法的局限性,实现事件委托,jQuery 1.3引入了.live()方法。后来,为解决“事件传播链”过长的问题,jQuery 1.4又支持为.live()方法指定上下文对象。而为了解决无谓生成元素集合的问题,jQuery 1.4.2干脆直接引入了一个新方法.delegate()。

使用.delegate(),前面的例子可以这样写:

$("#info_table").delegate("td","click",function(){/*显示更多信息*/});

使用.delegate()有如下优点(或者说解决了.live()方法的如下问题):

  • 直接将目标元素选择符("td")、事件("click")及处理程序与“受拖方”$("#info_table")绑定,不额外收集元素、事件传播路径缩短、语义明确;
  • 支持在连缀的DOM遍历方法后面调用,即支持$("table").find("#info").delegate...,支持精确控制;

可见,.delegate()方法是一个相对完美的解决方案。但在DOM结构简单的情况下,也可以使用.live()。

提示:使用事件委托时,如果注册到目标元素上的其他事件处理程序使用.stopPropagation()阻止了事件传播,那么事件委托就会失效。

结论

在下列情况下,应该使用.live()或.delegate(),而不能使用.bind():

  • 为DOM中的很多元素绑定相同事件;
  • 为DOM中尚不存在的元素绑定事件;

PS:根据jQuery 1.7 Beta 1的发版说明,jQuery 1.7为了解决.bind()、.live()和.delegate()并存造成的不一致性问题,将会增加一对新的事件方法:.on()和.off():
$(elems).on(events, selector, data, fn);
$(elems).off(events, selector, fn);
如果指定selector,则为事件委托;否则,就是常规绑定。新旧API对应如下:
enter image description here

(注:本文基于《jQuery基础教程(第3版)》相关章节内容编撰而成

如何减少浏览器的repaint和reflow

分类:网站建设  来源:网络  时间:Apr 11, 2012 9:11:27 PM

文本内容主要包括以下几点:

  1. 什么是repaint/reflow?
  2. 什么情况下会触发浏览器的repaint/reflow?
  3. 浏览器自身所作的优化
  4. 如何优化你的脚本来减少repaint/reflow?

一、什么是repaint/reflow?

页面在加载的过程中,需要对文档结构进行解析,同时需要结合各种各样的样式来计算这个页面长什么样子,最后再经过浏览器的渲染页面就出现了。这整个过程细说起来还是比较复杂,其中充满了repaint和reflow。对于DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式(浏览器的、开发人员定义的等)来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow;当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为repaint。

以上提到的只是在页面加载时必然会出现的repaint和reflow,除此之外,在页面加载完成后,用户的一些操作、脚本的一些操作都会导致浏览器发生这种行为,具体在后文阐述。

二、什么情况下会触发浏览器的repaint/reflow?

除了页面在首次加载时必然要经历该过程之外,还有以下行为会触发这个行为:

  • DOM元素的添加、修改(内容)、删除( Reflow + Repaint)
  • 仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)
  • 应用新的样式或者修改任何影响元素外观的属性
  • Resize浏览器窗口、滚动页面
  • 读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE))

在继续下面的文章之前,先介绍一款强大的性能分析工具-dynaTrace,借助该功能能够清晰的得到页面中的资源消耗情况,从而对症下药。另外,更细节的方面是它可以跟踪每个函数调用所造成的CPU消耗、Repaint/Reflow。接下来就借助该工具来测试一下以上描述的几点情况。

DOM元素的增删改

先看代码

  1. <!DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01//EN""http://www.w3c.org/TR/html4/strict.dtd">
  2. <html>
  3. <body>
  4. <divid="test1"onclick="addNode()">这里是第1个节点</div>
  5. <divid="test2"onclick="modNode()">这里是第2个节点</div>
  6. <divid="test3"onclick="delNode()">这里是第3个节点</div>
  7. </body>
  8. <scripttype="text/javascript">
  9. function$(id){
  10. returndocument.getElementById(id);
  11. }
  12. functionaddNode(){
  13. varn=document.createElement(¹div¹);
  14. n.innerHTML=¹NewNode¹;
  15. $(¹test1¹).appendChild(n);
  16. }
  17. functionmodNode(){
  18. $(¹test2¹).innerHTML=¹hello¹;
  19. }
  20. functiondelNode(){
  21. $(¹test3¹).parentNode.removeChild($(¹test3¹));
  22. }
  23. </script>
  24. </html>

 

在依次点击完每一个按钮后,我们来看看dynaTrace的情况,首先是一目了然的点击事件分布

image

放大之后来看一下每个事件的repaint/reflow情况:

增加节点:

image

修改节点:

image

删除节点:

image

图中的绿色部分表示的是reflow和repaint过程,其中比较短的绿条标示的reflow过程,后面长条部分表示的是repaint过程。从图中可以看出,对DOM节点的增删改都会造成reflow和repaint,由于改动小所以reflow消耗的时间很短,但是由于repaint是全局的,因此消耗的时间都比较长。

修改DOM元素前景色
  1. varn=$(¹colorNode¹);
  2. n.style.color=¹red¹;

 

image

从上图中可以看到修改字体颜色后,浏览器只有repaint而没有reflow。接下来试试修改背景色:

  1. varn=$(¹colorNode¹);
  2. n.style.backgroundColor=¹red¹;

 

image

由图中可以看出,修改背景色也会造成reflow和repaint。另外,经过测试发现,只要是修改元素的cssText属性,不论它的值是什么,都会导致浏览器reflow和repaint,因此在某些时候选择特定的样式属性赋值会有更好的效果。

Resize浏览器窗口以及拖动滚动条

image

测试中的操作如下:缩小浏览器窗口->放大浏览器窗口->拖动页面滚动条至页面底部。从图中可以看到Resize浏览器窗口以及拖动滚动条都会造成浏览器的repaint,而且CPU的消耗也比较大,尤其是拖动滚动条的时候。

读取Layout属性

根据各种参考资料中的描述,在用Javascript读取DOM节点的Layout属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE)) 的时候也会触发repaint,不过在以下的测试例子中并没有发现这一点。

  1. varn=$(¹colorNode¹);
  2. vartemp=document.documentElement.currentStyle;
  3. temp=n.offsetTop;
  4. temp=n.offsetLeft;
  5. temp=n.offsetWidth;
  6. temp=n.offsetHeight;
  7. temp=n.scrollTop;
  8. temp=n.scrollHeight;
  9. alert(temp);

 

image

三、浏览器优化

浏览器对于每一个渲染动作并不是立即执行,而是维护了一个渲染任务队列,浏览器会根据具体的需要分批集中执行其中的任务。除了浏览器自身维护的定期调度之外,脚本中的某些操作会导致浏览器立即执行渲染任务,例如读取元素的Layout属性。

  1. varbodystyle=document.body.style;
  2. varcomputed;
  3. if(document.body.currentStyle){
  4. computed=document.body.currentStyle;
  5. }else{
  6. computed=document.defaultView.getComputedStyle(document.body,¹¹);
  7. }
  8.  
  9. //每次都读取
  10.  
  11. bodystyle.color=¹red¹;
  12. bodystyle.padding=¹1px¹;
  13. tmp=computed.backgroundColor;
  14. bodystyle.color=¹white¹;
  15. bodystyle.padding=¹2px¹;
  16. tmp=computed.backgroundImage;
  17. bodystyle.color=¹green¹;
  18. bodystyle.padding=¹3px¹;
  19. tmp=computed.backgroundAttachment;
  20.  
  21. //最后再读取
  22.  
  23. bodystyle.color=¹yellow¹;
  24. bodystyle.padding=¹4px¹;
  25. bodystyle.color=¹pink¹;
  26. bodystyle.padding=¹5px¹;
  27. bodystyle.color=¹blue¹;
  28. bodystyle.padding=¹6px¹;
  29. tmp=computed.backgroundColor;
  30. tmp=computed.backgroundImage;
  31. tmp=computed.backgroundAttachment;

 

每次读取的渲染图:

image

最后读取的渲染图:

image

四、如何优化你的脚本来减少reflow/repaint?

1. 避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行,具体的方法包括但不完全包括以下几种:

(1). 先将元素从document中删除,完成修改后再把元素放回原来的位置

(2). 将元素的display设置为”none”,完成修改后再把display修改为原来的值

(3). 如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入document

  1. functionappendEveryTime(){
  2. for(vari=5000;i--;){
  3. varn=document.createElement(¹div¹);
  4. n.innerHTML=¹node¹+i;
  5. document.body.appendChild(n);/*每次创建的新节点都append到文档*/
  6. }
  7. }
  8.  
  9. functionappendLast(){
  10. varfrag=document.createDocumentFragment();
  11. for(vari=5000;i--;){
  12. varn=document.createElement(¹div¹);
  13. n.innerHTML=¹node¹+i;
  14. frag.appendChild(n);/*每次创建的节点先放入DocumentFragment中*/
  15. }
  16. document.body.appendChild(frag);
  17. }

 

用dynaTrace观察的结果如下,appendLast的性能无论是在Javascript的执行时间以及浏览器渲染时间方面都优于appendEveryTime。

appendEveryTime:

image

appendLast:

image

2. 集中修改样式

(1). 尽可能少的修改元素style上的属性

(2). 尽量通过修改className来修改样式

(3). 通过cssText属性来设置样式值

如下的代码中,每一次赋值都会造成浏览器重新渲染,可以采用cssText或者className的方式

  1. el.style.color=¹red;
  2. el.style.height=¹100px¹;
  3. el.style.fontSize=¹12px¹;
  4. el.style.backgroundColor=¹white¹;

 

3. 缓存Layout属性值

对于Layout属性中非引用类型的值(数字型),如果需要多次访问则可以在一次访问时先存储到局部变量中,之后都使用局部变量,这样可以避免每次读取属性时造成浏览器的渲染。

  1. varwidth=el.offsetWidth;
  2. varscrollLeft=el.scrollLeft;

 

4. 设置元素的position为absolute或fixed

在元素的position为static和relative时,元素处于DOM树结构当中,当对元素的某个操作需要重新渲染时,浏览器会渲染整个页面。将元素的position设置为absolute和fixed可以使元素从DOM树结构中脱离出来独立的存在,而浏览器在需要渲染时只需要渲染该元素以及位于该元素下方的元素,从而在某种程度上缩短浏览器渲染时间,这在当今越来越多的Javascript动画方面尤其值得考虑。

  1. <bodystyle="position:relative">
  2. <divid="test"style="background-color:red;width:100px;position:relative;">AnimationHere</div>
  3. </body>
  4. <scripttype="text/javascript">
  5. function$(id){
  6. returndocument.getElementById(id);
  7. }
  8. window.onload=function(){
  9. vart=$(¹test¹);
  10.  
  11. ~function(){
  12. tt.style.left=t.offsetLeft+5+¹px¹;
  13. tt.style.height=t.offsetHeight+5+¹px¹;
  14. setTimeout(arguments.callee,500);
  15. }();
  16. }
  17. </script>

 

通过修改#test元素的postion为relative和postion分别得到如下两个测试结果

position: relative

image

position: absolute

image

在postion:relative的测试当中,浏览器在重新渲染时做的工作比position:absolute多了不少。

如何使用HTML5实现拍照上传

分类:HTML  来源:网络  时间:Apr 11, 2012 9:08:15 PM

在HTML5规范的支持下,WebApp在手机上拍照已经成为可能。在下面,我将讲解Web App如何用手机进行拍照,显示在页面上并上传到服务器。

1、 视频流

HTML5 The Media Capture API提供了对摄像头的可编程访问,用户可以直接用getUserMedia获得摄像头提供的视频流。我们需要做的是添加一个HTML5的Video标签,并将从摄像头获得视频作为这个标签的输入来源(请注意目前仅Chrome和Opera支持getUserMedia)。

[html]

  1. <videoid="video"autoplay=""></video>
  2. <script>
  3. varvideo_element=document.getElementById(¹video¹);
  4. if(navigator.getUserMedia){//operashoulduseopera.getUserMedianow
  5. navigator.getUserMedia(¹video¹,success,error);
  6. }
  7. functionsuccess(stream){
  8. video_element.src=stream;
  9. }
  10. </script>

 

视频流

2、 拍照

拍照功能,我们采用HTML5的Canvas实时捕获Video标签的内容,Video元素能作为Canvas图像的输入,这一点很棒。主要代码如下:

[html]

  1. <script>
  2. varcanvas=document.createElement(¹canvas¹);
  3.  
  4. varctx=canvas.getContext(¹2d¹);
  5. varcw=vw;
  6. varch=vh;
  7. ctx.fillStyle="#ffffff";
  8. ctx.fillRect(0,0,cw,ch);
  9. ctx.drawImage(video_element,0,0,vvw,vvh,0,0,vw,vh);
  10. document.body.append(canvas);
  11. </script>

 


3、 图片获取

下面我们要从Canvas获取图片数据,其核心思路是用canvas的toDataURL将Canvas的数据转换为base64位编码的PNG图像,类似于“data:image/png;base64,xxxxx”的格式。

[html]

  1. varimgData=canvas.toDataURL("image/png");

 

因为真正图像数据是base64编码逗号之后的部分,所以我们实际服务器处理的图像数据应该是这部分,我们可以用两种办法来获取。

第一种:是在前端截取22位以后的字符串作为图像数据,例如:

[html]

  1. vardata=imgData.substr(22);

 

如果要在上传前获取图片的大小,可以使用:

[html]

  1. varlength=atob(data).length;//atobdecodesastringofdatawhichhasbeenencodedusingbase-64encoding

 

第二种:是在后端获取传输的数据后用后台语言截取22位以后的字符串。例如PHP里:

[html]

  1. $image=base64_decode(str_replace(¹data:image/jpeg;base64,¹,¹¹,$data);

 

4、 图片上传

在前端可以使用Ajax将上面获得的图片数据上传到后台脚本。例如使用jQuery时:

[html]

  1. $.post(¹upload.php¹,{¹data¹:data});

 

在后台我们用PHP脚本接收数据并存储为图片。

[html]

  1. functionconvert_data($data){
  2. $image=base64_decode(str_replace(¹data:image/jpeg;base64,¹,¹¹,$data);
  3. save_to_file($image);
  4. }
  5. functionsave_to_file($image){
  6. $fp=fopen($filename,¹w¹);
  7. fwrite($fp,$image);
  8. fclose($fp);
  9. }

 

请注意,以上的解决方案不仅能用于Web App拍照上传,并且你可以实现把Canvas的输出转换为图片上传的功能。这样你可以使用Canvas为用户提供图片编辑,例如裁剪、上色、涂鸦的画板功能,然后把用户编辑完的图片保存到服务器上。

Canvas涂鸦功能

在HTML5的驱动下,Web App与Native App之间是否还有不可逾越的鸿沟?我将会在3月23日百度开发者大会上现场来解答这个问题,敬请期待。

相关规范:

The MediaCapture API:http://www.w3.org/TR/media-capture-api/

Canvas:http://dev.w3.org/html5/2dcontext/

了解豌豆荚2.0背后的技术故事

分类:互联网  来源:网络  时间:Apr 11, 2012 9:04:43 PM

前不久,@豌豆实验室发布了豌豆荚2.0版本,发布会后,InfoQ采访到了软件工程师范怀宇(@duguguiyu)和高级软件工程师高雄(@Rock_gao),针对豌豆荚的技术特性和Webkit技术进行了采访。本文将为您揭开豌豆荚2.0神秘的面纱,带您走近“快速、简单、有爱”的设计理念背后的技术故事:

InfoQ:豌豆荚2.0中使用到了HTML5技术,主要的应用场景有哪些,与Chrome有什么区别?

高雄:我们和Chrome最大的区别在于Chrome基于Chromium,它也是Webkit核心,它的Webkit核心上面对于HTML5的支持做得非常全面。但我们只是简单基于Webkit来做的,这使得我们在HTML5支持上面会有一些难度,对HTML5支持也没有Chrome那么全面。当我们的前端工程师需要HTML5支持时,我们会在Windows平台上把HTML5支持添加上。比如说我们会实现HTML5的LocalStorage以及Notification这些特性。

范怀宇:在豌豆荚2.0中,收到短信时会出现一个弹出框,这就是利用HTML5的Notification机制实现的,与传统Windows弹框不同,类似于Gmail中的弹出框。在询问是否使用某种功能时,我们会将用户的选择通过LocalStorage来存储,与传统的方式相比,这种方法会高效很多。

InfoQ:豌豆荚是国内首家大规模使用Webkit技术开发的非浏览器软件,你们怎么想到用这样的一个技术,在选型时又做了哪些尝试呢?

范怀宇:其实都会有所考量,我们也会去了解Chrome这样的产品,它也是客户端应用,而且加载页面和绘制的速度都非常快,所以我们就认为这个技术用在其他软件开发上也应该是可行的。

高雄:这正是豌豆荚区别于其他PC软件的一个最重要的地方,我们虽然不是浏览器,而是一个PC上面的软件,但是我们也会用到Webkit。这更体现出我们一个超前的意识,我们现在看Chrome或者是其他一些浏览器,对新技术的支持都越来越重视,比如像对HTML5的支持,对于其它PC上应用来说,可能以后就与HTML5分道扬镳了。

InfoQ:主要用到了Webkit的哪些特性?能不能列举三点。

高雄:在国内来讲,我们对Webkit的应用还算比较深入。比如Webkit在Windows平台上的Porting并不是特别完善,我们就将它的图形库换成了SKIA图形库,从而使得豌豆荚2.0在渲染的速度和渲染的效果上都会好很多 。 第二点,我们把Webkit原生的网络库换成了IE的网络库,这样使得在豌豆荚2.0中我们可以复用IE缓存,同时这为豌豆荚2.0带来了更快的加载速度。 第三点,我们为Webkit做了很多JS扩展,并开发了一个名为OneRing的架构。

InfoQ:在开发豌豆荚的产品研发中,遇到了哪些问题,这些问题是怎么解决的?

高雄:虽然Webkit对HTML5支持已非常完善,但也仅仅是在Safari或Chrome的平台上。对于开发PC端软件来说,Chrome和Safari都比较重。所以只有Webkit比较适合,但是Webkit在Windows上面的porting有相当大的难度,而且对HTML5支持也很有限,有很多HTML5功能都需要自己去实现,这是一个非常大的难度。

另外,对JS进行深入扩展也是一个难点,在扩展时,要遵循HTML5的标准去做,还要考虑如何来管理扩展出的JS对象,否则就会出现内存泄露,或是垃圾回收等一系列问题,这一点我们仍然在不断地探索之中。

InfoQ:GECKO与Webkit比起来,有什么区别,为什么会选择Webkit,而不用那个,那个技术是不是有一些局限性?在用Webkit过程中,有没有哪些可以注意的技术细节?

高雄:首先回答第一个问题,为什么不用GECKO。GECKO的代码,如果对它的内核不是了解得非常深入的话,看起来是非常困难的,加之它的可读性也较差。此外,对CSS3、HTML4、HTML5标准的支持上,GECKO跟Webkit相比仍有一定差距。而且对旧标准支持上,比如CSS和HTML4,GECKO的得分都不是一百分,但Webkit是一百分,所以从标准支持上来说,显然Webkit要比GECKO好得多。

其次,从整个内核的加载速度和解析的性能上来说,Webkit也是强于GECKO的。

第二个问题,Webkit是一个开源项目,国内用Webkit比较多的仍是一些浏览器公司,他们用Webkit主要作为一个仿IE内核一样去用,就是做一些渲染或是网页加载这样的事情。但我觉得真正用Webkit,更重要的还是要分析它里面的一些基础架构和机制,这样的话,当我们在做PC软件或是其他平台软件时,都会比较得心应手,这是我对想从事Webkit开发工作朋友的一点建议。 另外,Webkit项目每天大概有一百到二百个commit,如果对Webkit非常感兴趣的话,我建议都花时间阅读一下。并且最好保持Webkit每天的update,这也是非常重要的。

InfoQ:我觉得豌豆荚2.0一个很明显的特点,就是速度非常快,包括很多用Webkit做内核的浏览器也是在追求速度,所以我想问一下,使用Webkit技术在提升速度方面,是有那些技巧可以简单介绍一下。

高雄:我们的速度相比较Chrome来说可能会稍慢一点,我最近了解到Chrome有一个新的技术,叫SPDY,这项技术通过在网络层使用新的机制来提升网络传输速度,这点对于Chrome速度的影响非常大,提升的效率也很高。对于我们来说,我们目前还没有引进这套技术,在速度提升方面主要表现在两个方面,一个是我们在处理网络传输时,会采用一些数据压缩的处理。另外一点,通过缓存来提升速度,这是我们在改进网络速度方面做的最重要两点。 接下来我们想引进Chrome的SPDY技术,来进一步提升我们的速度。

InfoQ:刚才也提到了有一个开发框架,在不远的将来会开源,能不能给我们介绍一下这个框架,这个框架主要是包含哪几个部分,主要解决什么问题?

范怀宇:首先最重要的是OneRing,我们把Webkit扩展之后,能够真正将Web开发放到Windows上来,Web开发工程师,可以完全写纯Web代码,后面也可以运行。这整个实现部分,我们都会开源。 在Webkit方面我们也会有一些开源的举措,这里面可能包含着我们对Webkit的扩展、改进,对HTML5的支持等等,最后的形式可能会是一个打包形式。 此外,我们还会把整个协议定义好,将接口事先都定义好,同时还有一些Windows的接口调用也要处理好,然后再将其开源。

InfoQ:咱们在OneRing的基础上做了哪些改进?

范怀宇:最重要的是异步调用,原来是纯同步的原理,但是当你真正做大型软件时,就会立刻发现问题,这样的方式是走不通的。然后还有线程安全,这样做的目的是要保证数据是安全的。

InfoQ:咱们在1.0版的时候看过一个金山网络的评测,关于几款手机管理软件会有一些安全方面的漏洞,豌豆荚2.0在安全上有哪些改进?

范怀宇:2.0最初的状态不会有这个隐患的,包括我们在刚刚设计2.0的时候,就把安全放到了很重要的程度,PC连接手机之前,会通过通信协议来交换密钥,交换密钥成功后才会保持连接。当有一些错误密钥出现时,手机会拒绝访问,多次出现后,手机就不会给这个客户端传输任何数据。在WIFI连接上,加强了密钥输入,在通讯的安全性上也做了很多事情。

InfoQ:从软件方面,因为用户从应用商店下载软件,软件会有一些漏洞之类的,当然软件商店会有检测,如果它没有检测好,用户从咱们这儿下载了,可能也会对接到咱们这边,对这方面的安全咱们会不会有过滤?

范怀宇:这方面的事情我们在1.0就做了,我们目前的一个解决方案是借助一些第三方专业的力量,比如说在1.0,如果你下一个应用,它会经过360扫描,QQ扫描,还有金山这样的公司,我们会调用他们的扫描借口,把这些应用全部扫描一遍,然后告诉用户这个东西在哪个扫描软件下是不安全的,然后由用户来决定是否继续安装。在2.0上我们会做更多这样的事情,但我们毕竟不是安全厂商,做这方面没有那么专业,所以目前的策略可能是通过合作的方式来解决这个问题。

InfoQ:咱们豌豆荚团队在开发过程中遇到哪些问题,因为毕竟豌豆荚2.0经历了十个月,可否为我们的技术爱好者分享一些你们在开发过程中遇到的一些比较有趣的问题。

范怀宇:早期我们碰到一个问题是数据的序列化和反序列化,这样的过程会比较耗时,我们尝试了很多种方案,从而将速度提升了很多倍,现在整个传输没有任何问题了,我们也会用一些更高压缩比的方法来解决传输问题。

在整个UI框架开发过程中,很多时候会面临前端需要什么技术支持、Webkit需要定制的问题,加上Webkit还是个非常庞大的项目,随时会有一些陷井在里面,加之我们也是在Webkit上不断地尝试,所以这一块也耗费了我们很大的精力。

但是,整个框架真的是节省了我们很多时间,前端如此多的界面,还有很多复杂的效果,只有两位前端工程师在做,高雄一个人在负责使用Webkit碰到的各种各样的问题,真的说豌豆荚十个月,我们耗了很多精力是在后端,很多业务逻辑要处理得很细致,然后各种各样的状况。其实后端逻辑会是我们开发量最大的一部分,包括从手机上读取各种数据,我们2.0做了一个最大的改变就是离线缓存,你可以不插手机,如果记住设备之后,你可以不插手机,随时可以看到手机上任何数据,比如你要找个联系人,你根本不用带手机,如果是你们家电脑,你做了离线存储,你直接打开电脑就可以看到数据,这些1.0完全没有的,我们在这上面也花了很多很多的时间。前端整个架构来说,相当于是三个人。

HTML5新特性:范围样式

分类:HTML  来源:网络  时间:Apr 11, 2012 9:03:09 PM

Chromium最近实现了一个HTML5的新特性:范围样式,又叫做<style scoped>。开发者可以通过为根元素设定一个添加了scoped属性的style标签,来限制样式只作用于style标签的子元素上。这会限制样式只影响style标签的父元素和它所有的后代元素。

例子

下面是一个使用了标准样式的简单页面:

 

<html>
<body>
 <div>a div! <span>a span!</span></div>
 <div>
 <style>
 div { color: red; }
 span { color: green; }
 </style>
 a div! <span>a span!</span></div>
 <div>a div! <span>a span!</span></div>
</body>
</html>

 

它设定的样式规则将使得所有的<div>变为红色,<span>变成绿色:

a div!a span!
a div!a span!
a div!a span!

然而,如果我们为<style>元素设置了scoped属性:

 

<html>
<body>
 <div>a div! <span>a span!</span></div>
 <div>
 <style scoped>
 div { color: red; }
 span { color: green; }
 </style>
 a div! <span>a span!</span></div>
 <div>a div! <span>a span!</span></div>
</body>
</html>

 

那么这个样式规则限制使得它们应用于<style scoped>元素的父<div>元素及其内部的所有元素上。我们称之为“范围”,结果如下所示:

a div! a span!
a div!a span!
a div! a span!

当然我们可以在任何地方使用这个标签。所以如果你喜欢冒险,你可以在一个范围样式内添加尽可能多的范围样式来获取尽可能细的样式控制粒度。

用途

它有什么好处?

一种常见的用途是内容合并:当你作为一个网站的作者想嵌入来自第三方的内容(译者注:想想博客),包括它所有的样式风格,但是不想让这些样式“污染”页面其他无关的部分。其一个巨大的优势是可以将其他网站例如Yelp、Twitter、Ebay等的内容合并到一个单独页面,而无需使用<iframe>或者动态的编辑外部内容来隔离它们。

如果你使用内容管理系统(CMS),它会发送许多标记片段来整合成为一个最终显示的页面。所以范围样式是一个伟大的功能,可以确保每一个片段与任何其他页面上的样式相隔离。这对wiki来说也一样的有用。

当你想在页面上展示一些漂亮的演示代码,很容易限制样式只作用于演示内容。你可以在演示随意的添加样式,而不用担心对页面上其他内容的影响。

它的另一个用途是简单的封装:例如,如果你的网页有一个侧边菜单,把指向菜单的样式封装到其中的<style scoped>段落会很有意义。这些样式规则对页面其他区域的渲染将不会有任何影响,这可以使得它可以很好地和主要内容进行分离!

它可能最引人注目的用途之一是用在Web组件模型上。Web组件将是一个构建像滑块、菜单、日期选择器和选项卡部件等的伟大方式。通过提供范围内的样式,设计人员可以构建一个组件并且将其打包成为一个独立的单位,其他人可以使用这个组件并组合为一个富Web应用程序。我们计划在Web组件和shadowDOM(已经可以在chrome://flags里开启实验性的“Shadow DOM”标志来启用)里大量使用范围样式。除了例如内联样式这样不好的方式,现在没有真正的好办法来确保样式限制在Web组件里,所以范围样式是一个完美的解决方案。

为什么包括父元素?

最自然的方式需要包括父元素,以便于<style scoped>规则可以来做为整个区域设置通用背景颜色这样类似的事情。它还允许采用“防守性”的方式来书写范围样式,通过为ID或者类选择器加上前缀的方式为还不支持<style scoped>的浏览器提供优雅降级。

 

<div id=”menu”>
 <style scoped>
 #menu .main { … }
 #menu .sub { … }

 

这种模仿可以实现“范围样式”的效果,但是因为更复杂的选择器会有一些运行时的性能损失。这种做法的好处是,它采用一个优雅的降级方法让我们可以等到<style scoped>被广泛支持和ID选择器可以简单地被丢弃时。

状态

鉴于范围样式的实现是最新的,它目前被隐藏在Chrome的运行时标志里。要激活它,你需要下载版本号为19或者更高的Chrome(现在的Chrome Canary),然后在chrome://flags里找到“开启<stylescoped>”选项(靠近最后),单击“启用”,然后重新启动浏览器。

目前没有已知bug,但是@keyframes和@-webkit-region区域范围的版本还正在实现中。此外,@font-face被忽略掉了,因为现在有一个很好的机会来调整这个规范。

我们鼓励每个对这个特性感兴趣的人都来尝试一下,让我们知道你的反馈:好、不好以及(可能)不足。

  • 60
  • |<
  • <<
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • >>
  • >|