Be a Pure Person, Enjoy a Simple Life

01月 26

几个超实用的JavaScript技巧及最佳实践

1.第一次给变量赋值时,别忘记var关键字
如果初次赋值给未声明的变量,该变量会被自动创建为全局变量,在JS开发中,应该避免使用全局变量,这是大家容易忽略的错误。

2.使用===而非==
并且永远不要使用=或!=。

[10] === 10    // is false  
[10]  == 10    // is true  
'10' == 10     // is true  
'10' === 10    // is false  
 []   == 0     // is true  
 [] ===  0     // is false  
 '' == false   // is true but true == "a" is false  
 '' ===   false // is false  

3.使用分号来作为行终止字符
在行终止的地方使用分号是一个很好的习惯,即使开发人员忘记加分号,编译器也不会有任何提示,因为在大多数情况下,JavaScript解析器会自动加上。

  function Person(firstName, lastName){  
        this.firstName =  firstName;  
        this.lastName = lastName;          
    }    
      
    var Saad = new Person("Saad", "Mousliki"); 

5.小心使用typeof、instanceof和constructor

var arr = ["a", "b", "c"];  
typeof arr;   // return "object"   
arr  instanceof Array // true  
arr.constructor();  //[]
 

6.创建一个自调用(Self-calling)函数
通常被称为自调用匿名函数或即刻调用函数表达式(LLFE)。当函数被创建的时候就会自动执行,如下:

 (function(){  
        // some private code that will be executed automatically  
    })();    
    (function(a,b){  
        var result = a+b;  
        return result;  
    })(10,20)  

7.给数组创建一个随机项

var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119];  
var  randomItem = items[Math.floor(Math.random() * items.length)];  

8.在特定范围里获得一个随机数
下面这段代码非常通用,当你需要生成一个测试的数据时,比如在最高工资和最低工资之间获取一个随机数的话。

var x = Math.floor(Math.random() * (max - min + 1)) + min;

9.在数字0和最大数之间生成一组随机数

 var numbersArray = [] , max = 100;  
for( var i=1; numbersArray.push(i++) < max;);  // numbers = [0,1,2,3 ... 100]  

10.生成一组随机的字母数字字符

 function generateRandomAlphaNum(len) {  
        var rdmstring = "";  
        for( ; rdmString.length < len; rdmString  += Math.random().toString(36).substr(2));  
        return  rdmString.substr(0, len);  
      
    }  

11.打乱数字数组

   var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];  
    numbers = numbers.sort(function(){ return Math.random() - 0.5});  
    /* the array numbers will be equal for example to [120, 5, 228, -215, 400, 458, -85411, 122205]  */  

12.字符串trim函数
trim函数可以删除字符串两端的空白字符,可以用在Java、C#、PHP等多门语言里。

String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g, "");};

13.数组追加

var array1 = [12 , "foo" , {name "Joe"} , -2458];  
var array2 = ["Doe" , 555 , 100];  
Array.prototype.push.apply(array1, array2);  
/* array1 will be equal to  [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */  

14.将参数对象转换为数组

var argArray = Array.prototype.slice.call(arguments); 

15.验证一个指定参数是否为数字

function isNumber(n){  
    return !isNaN(parseFloat(n)) && isFinite(n);  
}  
 

16.验证一个给定的参数为数组

function isArray(obj){  
        return Object.prototype.toString.call(obj) === '[object Array]' ;  
    }

注意,如果toString()方法被重写了,你将不会得到预期结果。
或者你可以这样写:

  Array.isArray(obj); // its a new Array method  

同样,如果你使用多个frames,你可以使用instancesof,如果内容太多,结果同样会出错。

var myFrame = document.createElement('iframe');  
    document.body.appendChild(myFrame);  
      
    var myArray = window.frames[window.frames.length-1].Array;  
    var arr = new myArray(a,b,10); // [a,b,10]    
      
    // instanceof will not work correctly, myArray loses his constructor   
    // constructor is not shared between frames  
    arr instanceof Array; // false  

17.从数字数组中获得最大值和最小值

var  numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];   
var maxInNumbers = Math.max.apply(Math, numbers);   
var minInNumbers = Math.min.apply(Math, numbers);  

18.清空数组

var myArray = [12 , 222 , 1000 ];    
myArray.length = 0; // myArray will be equal to [].  

19.不要用delete从数组中删除项目
开发者可以使用split来替代delete去删除数组中的项目。好的方式是使用delete去替换数组中undefined的数组项目,而不是使用delete去删除数组中项目。

 var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];   
items.length; // return 11   
delete items[3]; // return true   
items.length; // return 11   
/* items will be equal to [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154,       119]   */

应该如下使用

var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];   
items.length; // return 11   
items.splice(3,1) ;   
items.length; // return 10   
/* items will be equal to [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154,       119]   */ 

delete方法应该用来删除一个对象属性。

20.使用length属性截短数组
如上文提到的清空数组,开发者还可以使用length属性截短数组。

var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ];    
myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124].

如果你所定义的数组长度值过高,那么数组的长度将会改变,并且会填充一些未定义的值到数组里,数组的length属性不是只读的。

myArray.length = 10; // the new array length is 10   
myArray[myArray.length - 1] ; // undefined  

21. 使用逻辑AND/OR来处理条件语句

var foo = 10;  
foo == 10 && doSomething(); // is the same thing as if (foo == 10) doSomething(); 
foo == 5 || doSomething(); // is the same thing as if (foo != 5) doSomething();

逻辑AND也可以用来设置含糊参数缺省的值

Function doSomething(arg1){ 
    Arg1 = arg1 || 10; // arg1 will have 10 as a default value if it’s not already set
}

22. 使用map()函数方法来循环数组里的项目

var squares = [1,2,3,4].map(function (val) {  
    return val * val;  
}); 
// squares will be equal to [1, 4, 9, 16] 

23. 按小数点后N位来四舍五入

var num =2.443242342;
num = num.toFixed(4);  // num will be equal to 2.4432

24. 浮点问题

0.1 + 0.2 === 0.3 // is false 
9007199254740992 + 1 // is equal to 9007199254740992  
9007199254740992 + 2 // is equal to 9007199254740994

为什么? 0.1 + 0.2 等于 0.30000000000000004 。你应该知道所有的javascript数字在64位2进制内部都是使用浮点表示

这个来自于IEEE 754标准。更多信息介绍,请参考:相关博客

你可以使用上面介绍的toFixed()和toPrecision()来解决这个问题

25. 使用for-in循环来检查对象的指定属性

下面的代码片段非常实用,可以避免从对象的prototype来循环遍历对象的属性:

for (var name in object) {  
    if (object.hasOwnProperty(name)) { 
        // do something with name                    
    }  
}

26. 逗号操作符

var a = 0; 
var b = ( a++, 99 ); 
console.log(a);  // a will be equal to 1 
console.log(b);  // b is equal to 99

27. 缓存需要计算或者DOM查询的变量

使用jQuery的选择器,我们一定要记住缓存DOM元素,这样会提高执行效率:

var navright = document.querySelector('#right'); 
var navleft = document.querySelector('#left'); 
var navup = document.querySelector('#up'); 
var navdown = document.querySelector('#down');

28. 在传入isFinite()之前验证参数

isFinite(0/0) ; // false 
isFinite("foo"); // false 
isFinite("10"); // true 
isFinite(10);   // true 
isFinite(undifined);  // false 
isFinite();   // false 
isFinite(null);  // true  !!! 

29. 避免数组中index为负值

var numbersArray = [1,2,3,4,5]; 
var from = numbersArray.indexOf("foo") ;  // from is equal to -1 
numbersArray.splice(from,2);    // will return [5]

这里需要注意indexof的参数 不能为负值,但是splice可以

30. 序列化和反序列化(用来处理JSON)

var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} }; 
var stringFromPerson = JSON.stringify(person); 
/* stringFromPerson is equal to "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}"   */ 
var personFromString = JSON.parse(stringFromPerson);  
/* personFromString is equal to person object  */

31. 避免使用eval或者Function构建器

使用eval或者function构建器是一件非常消耗资源的操作,因为每次调用script引擎都必须将源代码转换为可执行的代码

var func1 = new Function(functionCode); //避免使用!!
var func2 = eval(functionCode);//避免使用!!

32. 避免使用with()

使用with()可以用来插入一个变量到全局。然而,如果另外一个变量拥有同样的名字,将会导致非常混乱并且会覆盖数值

33. 避免在数组中使用for-in循环

不推荐使用:

var sum = 0;  
for (var i in arrayNumbers) {  
    sum += arrayNumbers[i];  
}

如下代码将会更好:

var sum = 0;  
for (var i = 0, len = arrayNumbers.length; i < len; i++) {  
    sum += arrayNumbers[i];  
}

作为额外的好处,i和len的实例化都执行一次,因为都是循环中的第一个语句,但是比下面执行速度更快:

for (var i = 0; i < arrayNumbers.length; i++)

为什么? arrayNumbers的长度在每次循环都计算一次

34. 传递函数,而非字符串到setTimeout()和setInterval()中

如果你传递一个字符串到setTimeout和setInterval中,处理方式和eval将会类似,速度会很慢,不要使用如下:

setInterval('doSomethingPeriodically()', 1000);  
setTimeOut('doSomethingAfterFiveSeconds()', 5000);
推荐使用如下

setInterval(doSomethingPeriodically, 1000);  
setTimeOut(doSomethingAfterFiveSeconds, 5000);

35. 使用switch/case语句而非一系列的if/else

如果多余两个条件,使用switch/case将会更快,而且语法更优雅(代码组织的更好)。对于多余10个条件的避免使用。

36. 使用switch/case语句处理数值区域

使用如下小技巧处理数值区域:

function getCategory(age) {  
    var category = "";  
    switch (true) {  
        case isNaN(age):  
            category = "not an age";  
            break;  
        case (age >= 50):  
            category = "Old";  
            break;  
        case (age <= 20):  
            category = "Baby";  
            break;  
        default:  
            category = "Young";  
            break;  
    };  
    return category;  
}  
getCategory(5);  // will return "Baby"

37. 创建一个prototype是指定对象的对象

使用如下代码可以生成一个prototype是指定对象的对象:

function clone(object) {  
    function OneShotConstructor(){}; 
    OneShotConstructor.prototype= object;  
    return new OneShotConstructor(); 
} 
clone(Array).prototype ;  // []

**39. 一个HTMLescaper方法**

function escapeHTML(text) {  
    var replacements= {"<": "&lt;", ">": "&gt;","&": "&amp;", "\"": "&quot;"};                      
    return text.replace(/[<>&"]/g, function(character) {  
        return replacements[character];  
    }); 
}

编译:当然,前台处理并不安全,后台处理更彻底

40. 在循环中避免使用try-catch-finally

不要使用如下代码:

var object = ['foo', 'bar'], i;  
for (i = 0, len = object.length; i <len; i++) {  
    try {  
        // do something that throws an exception 
    }  
    catch (e) {   
        // handle exception  
    } 
}

使用这段代码:

var object = ['foo', 'bar'], i;  
try { 
    for (i = 0, len = object.length; i <len; i++) {  
        // do something that throws an exception 
    } 
} 
catch (e) {   
    // handle exception  
} 

40. 设置XMLHttpRequests的timeout

如果一个XHR花费了太多时间,你可以在XHR调用中使用setTimeout来退出连接:

var xhr = new XMLHttpRequest (); 
xhr.onreadystatechange = function () {  
    if (this.readyState == 4) {  
        clearTimeout(timeout);  
        // do something with response data 
    }  
}  
var timeout = setTimeout( function () {  
    xhr.abort(); // call error callback  
}, 60*1000 /* timeout after a minute */ ); 
xhr.open('GET', url, true);  
 
xhr.send();

额外的好处,你可以完全避免同步AJAX调用

41. 处理WebSocket timeout

一般来说,当一个websocket连接建立后,服务器可以在30秒无响应的情况下time out你的连接。防火墙也可以做到。

为了处理timeout问题,你可以定时发送一个空的消息到服务器。为了实现,你可以添加两个方法到你的代码中:

一个保证连接的存在,另外一个取消连接。使用这个技巧,你可以处理timeout问题:

var timerID = 0; 
function keepAlive() { 
    var timeout = 15000;  
    if (webSocket.readyState == webSocket.OPEN) {  
        webSocket.send('');  
    }  
    timerId = setTimeout(keepAlive, timeout);  
}  
function cancelKeepAlive() {  
    if (timerId) {  
        cancelTimeout(timerId);  
    }  
}

keepAlive函数可以添加到webSocket的onOpen函数的最后。cancelKeepAlive添加到webSocket的onClose函数最后。

42. 记住,操作符比函数调用更快

不推荐使用:

var min = Math.min(a,b); 
A.push(v);

推荐使用:

var min = a < b ? a:b; 
A[A.length] = v;

43. 不要忘记使用代码美化工具。
在代码产品化前使用JSLint和代码压缩工具(例如,JSMin)来处理

01月 20

什么是响应式Web设计?怎样进行?

响应式Web设计(Responsive Web design)的理念是,页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整。具体的实践方式由多方面组成,包括弹性网格和布局、图片、CSS media query的使用等。无论用户正在使用笔记本还是iPad,我们的页面都应该能够自动切换分辨率、图片尺寸及相关脚本功能等,以适应不同设备;换句话说,页面应该有能力去自动响应用户的设备环境。这样,我们就可以不必为不断到来的新设备做专门的版本设计和开发了。

响应式Web设计的概念

Ethan Marcotte曾经在A List Apart发表过一篇文章"Responsive Web Design",文中援引了响应式建筑设计的概念:

最近出现了一门新兴的学科——"响应式建筑(responsive
architecture)"——提出,物理空间应该可以根据存在于其中的人的情况进行响应。结合嵌入式机器人技术以及可拉伸材料的应用,建筑师们正在尝试建造一种可以根据周围人群的情况进行弯曲、伸缩和扩展的墙体结构;还可以使用运动传感器配合气候控制系统,调整室内的温度及环境光。已经有公司在生产"智能玻璃":当室内人数达到一定的阀值时,这种玻璃可以自动变为不透明,确保隐私。

将这个思路延伸到Web设计的领域,我们就得到了一个全新的概念。为什么一定要为每个用户群各自打造一套设计和开发方案?和响应式建筑相似,Web设计同样应该做到根据不同设备环境自动响应及调整。

显然,我们无法也无需使用运动传感器或是机器人技术,响应式Web设计更多需要的是抽象思维。好在,一些相关的概念已经得到了实践,比如液态布局、帮助页面重新格式化的media queries和脚本等。但是响应式Web设计不仅仅是关于屏幕分辨率自适应以及自动缩放的图片等等,它更像是一种对于设计的全新思维模式。

调整分辨率

不同的设备都有各自的屏幕分辨率、清晰度以及屏幕定向方式,不断被研发着的各种新设备也将带来新的屏幕尺寸规格。有些设备基于横屏(portrait),有些是竖屏(landscape),甚至还有正方形;对于日益流行的iPhone、iPad及其他一些智能手机、平板电脑,用户还可以通过转动设备来任意切换屏幕的定向方式。怎样才能做到让一种设计方案满足所有情况?

请输入图片描述

要想做到同时兼容横、竖屏(用户还有可能在页面加载的过程中切换方向),我们就必须考虑N种屏幕尺寸规格。诚然,我们可以将这些规格划分为几个大类,然后为每一类做一种方案,确保该方案至少在本组中尽量具有弹性。但即使这样,结果也将是无比焦虑的,谁知道某类设备在5年之后的占有率是多少?而且很多用户甚至不去将浏览器的窗口最大化;类似这样的变数,我们还要考虑多少呢?

Morten Hjerde和他的同事们对2005至2008年市场中的400余种移动设备进行了统计(查看报告),下图展示了大致的统计结果:

请输入图片描述

在08年之后,更多更有代表性的新设备问世并普及了。显然,我们不可以沿着"多方案"的思路继续走下去;那么我们应该怎样做呢?

部分解决方案:一切弹性化

几年前,弹性布局(flexible layout)几乎是一种奢侈品,所谓弹性,也只是体现在竖排布局以及字号等方面;图片始终可以轻易的破坏页面结构,而且即使是哪些弹性的元素结构,在很极端的情况下,仍会破坏布局。所以,所谓的弹性布局其实并非那样弹性,它有时甚至不能适应台式机与笔记本的屏幕分辨率差异,更不用说手机等移动设备了。

现在,我们可以通过响应式的设计和开发思路让页面更加"弹性"了。图片的尺寸可以被自动调整,页面布局再不会被破坏。虽然永远没有最完美的解决方案,但它给了我们更多选择。无论用户切换设备的屏幕定向方式,还是从台式机屏幕转到iPad上浏览,页面都会真正的富有弹性。

在前文提到的Ethan Marcotte的文章中,他通过一个实例展示了响应式Web设计在页面弹性方面的特性:

请输入图片描述
该实例的实现方式完美的结合了液态网格和液态图片技术,并且聪明的在正确的地方使用了正确的HTML标记。"液态网格"是一种很常见的实践方式;对于"液态图片"技术,下面的文章做了不错的介绍:

Hiding and Revealing Portions of Images

Creating Sliding Composite Images

Foreground Images That Scale With the Layout

说到创建液态页面,最好看看Zoe Mickley Gillenwater的那本《Flexible Web Design: Creating Liquid and Elastic Layouts with CSS》,或是下载个样章先:"怎样创建弹性图片"。另外,Zoe的这篇"Essential Resources for Creating Liquid and Elastic Layouts."提供了不少关于创建弹性网格和布局的教程、资源、创意指导和最佳实践方式。

从技术角度讲,虽然听上去这些都简单可行,但它比"将这些功能结合在一起"要复杂些。举个例子,仔细观察Ethan Marcotte提供的实例中的logo图片:

请输入图片描述

如果我们将浏览器窗口不断调小,会发现logo图片的文字部分始终会保持同比缩小,保证其完整可读,而不会和周围的插图一样被两边裁掉。所以整个logo其实包括两部分:插图作为页面标题的背景图片,会保持尺寸,但会随着布局调整而被裁切;文字部分则是一张单独的图片。

<h1 id="logo">

  <a href="#"><img src="site/logo.png" alt="The Baker Street Inquirer" /></a>

</h1>

其中,<h1>元素使用插图作为背景,文字部分的图片始终保持与背景的对齐。

这个实例小小的展示一下响应式Web设计的思路。不过这点小努力还不足以避免整个布局在小尺寸窗口中变的过窄或过短,并且logo文字最终会变的小到难以识别,背景图片也会被过多的裁切。

弹性图片

响应式Web设计的思路中,一个重要的因素是怎样处理图片方面的问题。有很多同比缩放图片的技术,其中有不少是简单易行的。其中,由Richard Rutter最先尝试的一种做法比较流行,即使用CSS的max-width属性。这个方法在Ethan Marcotte的液态图片一文中也有提到。

img { max-width: 100%;}
只要没有其他涉及到图片宽度的样式代码覆盖掉这一行规则,页面上所有的图片就会以其原始宽度进行加载,除非其容器可视部分的宽度小于图片的原始宽度。上面的代码确保图片最大的宽度不会超过浏览器窗口或是其容器可视部分的宽度,所以当窗口或容器的可视部分开始变窄时,图片的最大宽度值也会相应的减小,图片本身永远不会容器边缘隐藏和覆盖。实际上,就像Jason Grigsby在他的CSS Media Query for Mobile is Fool's Gold一文中提到的,"液态图片背后的思路,就是无论何时,都确保在其原始宽度范围内,以最大的宽度同比完整的显示图片。我们不必在样式表中为图片设置宽度和高度,只需要让样式表在窗口尺寸发生变化时辅助浏览器对图片进行缩放。" 一种简而美的方法。

图片本身的分辨率及加载时间是另外一个需要考虑的问题。虽然通过上面的方法,可以很轻松的缩放图片,确保在移动设备的窗口中可以被完整浏览,但如果原始图片本身过大,便会显著降低图片文件的下载速度,对存储空间也会造成没有必要的消耗。

响应式图片

由Filament Group提出的"响应式图片"技术思想,有助于解决上面提到的问题:不仅要同比的缩放图片,还要在小设备上降低图片自身的分辨率。可以看下demo页面先。

responsive-web-design-flexible-image-filamentgroup

这个技术的实现需要使用几个相关文件,我们可以在Github上获取。包括一个JavaScript文件(rwd-images.js),一个.htaccess文件,以及一些范例资源文件。具体使用方法可以参考Responsive Images的说明文档。大致的原理是,rwd-images.js会检测当前设备的屏幕分辨率,如果是大屏幕设备,则向页面head部分中添加BASE标记,并将后续的图片、脚本和样式表加载请求定向到一个虚拟路径"/rwd-router"。当这些请求到达服务器端,.htacces文件会决定这些请求所需要的是原始图片还是小尺寸的"响应式图片",并进行相应的反馈输出。对于小屏幕的移动设备,原始尺寸的大图片永远不会被用到。

这项技术支持多数的现代浏览器,包括IE8+、Safari、Chrome和Opera,以及这些浏览器的移动设备版本;在FireFox及一些旧浏览器中,则会优雅降级:我们仍可得到小图片的输出,但同时,原始大图也会被下载。

禁用iPhone中的图片自动缩放

在iPhone及iPod Touch中,页面会被自动的同比例缩小至最适合屏幕大小的尺寸,x轴不会产生滚动条,用户可以上下拖拽浏览全部页面,或在需要的时候放大页面的局部。这里会产生一个问题,即使我们运用响应式Web设计的思想,专门为iPhone的小屏输出小图片,它同样会随着整个页面一起被同比例缩小,如下图左侧所示。

responsive-web-design-iphone

我们可以使用苹果专有的一些meta标记来解决类似的问题。在页面的<head>部分添加以下代码(详情可以参考Think Vitamin的相关文章):

<meta name="viewport" content="width=device-width; initial-scale=1.0">

将initial-scale的值设定为"1",即可覆写默认的缩放方式,保持原始的尺寸及比例。更多关于viewport meta标记的用法,可以参考苹果官方的文档。

打造布局结构

当页面所需要适应的不同设备的屏幕尺寸差异过大时,除了图片方面,我们也应该考虑到整个布局结构的响应式调整;我们可以使用独立的样式表,或者更有效的,使用CSS media query。这不会引起多大的麻烦,多数样式设定不会被影响和改变,只有一些特定的元素会通过浮动、宽度和高度等的设置来改变位置。

我们可以使用一个默认主样式表来定义页面的主要结构元素,比如#wrapper、#content、#sidebar、#nav等的默认布局方式,以及一些全局性的配色和字体方案。

我们可以监测页面布局随着不同的浏览环境而产生的变化,如果它们变的过窄过短或是过宽过长,则通过一个子级样式表来继承主样式表的设定,并专门针对某些布局结构进行样式覆写。我们来看下代码示例:

下面的代码可以放在默认主样式表style.css中:

/* Default styles that will carry to the child style sheet */

html,body{

   background...

   font...

   color...

}


h1,h2,h3{}

p, blockquote, pre, code, ol, ul{}


/* Structural elements */

#wrapper{

    width: 80%;

    margin: 0 auto;

    background: #fff;

    padding: 20px;

}


#content{

    width: 54%;

    float: left;

    margin-right: 3%;

}


#sidebar-left{

    width: 20%;

    float: left;

    margin-right: 3%;

}

#sidebar-right{

    width: 20%;

    float: left;

}

下面的代码可以放在子级样式表mobile.css中,专门针对移动设备进行样式覆写:

#wrapper{

    width: 90%;

}


#content{

    width: 100%;

}


#sidebar-left{

    width: 100%;

    clear: both;


    /* Additional styling for our new layout */

    border-top: 1px solid #ccc;

    margin-top: 20px;

}


#sidebar-right{

    width: 100%;

    clear: both;


    /* Additional styling for our new layout */

    border-top: 1px solid #ccc;

    margin-top: 20px;

}

大致的视觉效果如下图所示:

responsive-web-design-moving-structure

Media Queries

CSS3支持CSS2.1所支持的所有媒体类型,例如screen、print、handheld等,同时添加了很多涉及媒体类型的功能属性,包括max-width(最大宽度)、device-width(设备宽度)、orientation(屏幕定向,横屏或竖屏)和color。在CSS3发布之后出现的新玩具,如iPad或Android相关设备,都可以完美的支持这些属性。所以我们可以通过media query为新设备设置独特的样式,而忽略那些不支持CSS3的台式机中的旧浏览器。

在Ethan的文章中,我们能看到一段media query使用实例:

<link rel="stylesheet" type="text/css" media="screen and (max-device-width: 480px)" href="shetland.css" />

代码本身可以很好的说明工作机制:如果页面通过屏幕呈现(非打印一类),并且屏幕宽度不超过480px,则加载shetland.css样式表。要了解更多关于CSS3媒体新属性的信息,可以参考"The Orientation Media Query"一文。

我们可以创建多个样式表,以适应不同设备类型的宽度范围。Ethan的文章中的"Meet the media query"部分有更多的范例及解释。更有效率的做法是,将多个media queries整合在一个样式表文件中:

/ Smartphones (portrait and landscape) ----------- /

@media only screen

and (min-device-width : 320px)

and (max-device-width : 480px) {

/ Styles /

}

/ Smartphones (landscape) ----------- /

@media only screen

and (min-width : 321px) {

/ Styles /

}

/ Smartphones (portrait) ----------- /

@media only screen

and (max-width : 320px) {

/ Styles /

}
上面的代码来自于Andy Clark创建的可以兼容各种主流设备的免费模板。这样整合多个media queries于一个样式表文件的方式,与通过media queries调用不同样式表的方式之间的区别与联系,可以参考"Hardboiled CSS3 Media Queries"一文。

CSS3 Media Queries

上面演示的一些代码范例是CSS2.1与CSS3通吃的。现在让我们来看看怎样使用CSS3专有的media queries功能来创建响应式Web设计。其中某些方法在当前就有切实的使用价值,不久的将来则一定会全部派上用场。

min-width和max-width这两个属性很靠谱。通过min-width的设置,我们可以在浏览器窗口或设备屏幕宽度高于这个值的情况下,为页面指定一个特定的样式表;max-width则反之。

下面的几个示例中,我们使用的是将多个media queries整合在单一样式表中进行编码的句法。如前文所述,这样做更加高效,减少请求数量。

@media screen and (min-width: 600px) {

 .hereIsMyClass {

      width: 30%;

      float: right;

 }

}
上面代码中定义的类(hereIsMyClass)只有在浏览器或屏幕宽度超过600px时才会有效。

@media screen and (max-width: 600px) {

 .aClassforSmallScreens {

      clear: both;

      font-size: 1.3em;

 }

}
而这段代码的作用则相反:aClassforSmallScreens类只有在浏览器或屏幕宽度小于600px时才会有效。

可以看出min-width和max-width可以同时判断设备屏幕尺寸与浏览器实际宽度。有些时候,我们希望通过media queries作用于某种特定的设备,而忽略其上运行的浏览器是否由于没有最大化而在尺寸上与设备屏幕尺寸产生不一致的情况。这时,我们需要使用min-device-width与max-device-width,用来判断设备本身的屏幕尺寸。

@media screen and (max-device-width: 480px) {

 .classForiPhoneDisplay {

      font-size: 1.2em;

 }

}
@media screen and (min-device-width: 768px) {

 .minimumiPadWidth {

      clear: both;

      margin-bottom: 2px solid #ccc;

 }

}
还有一些其他方法,可以帮我们有效的使用media queries锁定某些指定的设备。可以参考下面两篇出自Thomas Maier的文章:

CSS for iPhone 4 (Retina display)

How To: CSS for the iPad

对于iPad来说,orientation属性尤其有用。它的值可以是landscape(横屏)或portrait(竖屏)。

@media screen and (orientation: landscape) {

 .iPadLandscape {

      width: 30%;

      float: right;

 }

}

@media screen and (orientation: portrait) {

 .iPadPortrait {

      clear: both;

 }

}
不幸的是,这个属性目前确实只在iPad上有效。对于其他可以转屏的设备,譬如iPhone,可以使用min-device-width和max-device-width来变通实现;详情可以参考"Determine iPhone orientation using CSS"一文。

我们还可以将上述属性组合使用,来锁定某个屏幕尺寸范围:

@media screen and (min-width: 800px) and (max-width: 1200px) {

 .classForaMediumScreen {

      background: #cc0000;

      width: 30%;

      float: right;

 }

}
上面的代码可以作用于浏览器窗口或屏幕宽度在800px至1200px之间的所有设备。

其实,很多设计师和开发者仍会选择使用多个样式表的方式来实现media queries。如果从资源的组织和维护的角度出发,其益处确实高于效率的损耗的话,那么这样做也完全不坏:

<link rel="stylesheet" media="screen and (max-width: 600px)" href="small.css" />

<link rel="stylesheet" media="screen and (min-width: 600px)" href="large.css" />

<link rel="stylesheet" media="print" href="print.css" />

所以呐,凡事没有绝对,最好根据实际情况决定使用media queries的方式。比如,对于iPad,我们可以将多个media queries直接写在一个样式表中。因为iPad用户随时有可能切换屏幕定向,这种情况下,要保证页面在极短的时间内响应屏幕尺寸的调整,我们必须选择效率最高的方式。

JavaScript

JavaScript也是我们的武器之一,特别是当某些旧设备无法完美支持CSS3的media query时,它可以作为后备支援。幸运的是,已经有专门的JS库来帮助旧浏览器(IE 5+,Firefox 1+,Safari 2等)支持CSS3的media queries。使用方法很简单,下载css3-mediaqueries.js并在你的页面中调用它。

而下面的代码则演示了怎样使用简单的几行jQuery代码来检测浏览器宽度,并为不同的情况调用不同的样式表:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>

<script type="text/javascript">

    $(document).ready(function(){

        $(window).bind("resize", resizeWindow);

        function resizeWindow(e){

            var newWindowWidth = $(window).width();


            // If width width is below 600px, switch to the mobile stylesheet

            if(newWindowWidth < 600){
                 $("link[rel=stylesheet]").attr({href : "mobile.css"});
                 }             // Else if width is above 600px, switch to the large stylesheet
             else if(newWindowWidth > 600){

                $("link[rel=stylesheet]").attr({href : "style.css"});

            }

        }

    });

</script>

类似这样的解决方案还有很多。所以我们要清楚,media queries不是一个绝对唯一的答案,它只是一个以纯CSS方式实现响应式Web设计思路的手段。借助JavaScript,我们则可以实现更多的变化。这篇"Combining Media Queries and JavaScript"向我们展示了JavaScript配合media queries的更多细节信息。

显示或隐藏内容

通过前文的学习,我们已经了解到,对于响应式Web设计,同比例缩减元素尺寸以及调整页面结构布局,是两个重要的方式方法。但是对于页面中的文字内容信息来说,则不能简单的只从"同比缩小"和"调整布局结构"这两方面去处理。对于手机等移动设备来说,在文字内容方面,已经有了很多最佳实践方式和指导原则:简化的导航、更易聚焦的内容、以信息列表代替传统的多行文案内容等。

responsive-web-design-digg-app

响应式Web设计的思想,一方面要保证页面元素及布局具有足够的弹性,来兼容各类设备平台和屏幕尺寸;另一方面,则是增强可读性和易用性,帮助用户在任何设备环境中都能更容易的获取最重要的内容信息。

有一条样式代码,我们已经使用了多年:

display: none;
我们可以在一个针对某类小屏幕设备的样式表中使用它来隐藏掉页面中的某些块级元素,也可以使用前文的方法,通过JS判断当前硬件屏幕规格,在小屏幕设备的情况下直接为需要隐藏的元素添加工具类class。比如,对于手机类设备,我们可以隐藏掉大块的文字内容区,而只显示一个简单的导航结构,其中的导航元素可以指向详细内容页面。

注意,不要使用visibility: hidden的方式,因为这只能使元素在视觉上不做呈现;display属性则可帮助我们设置整块内容是否需要被输出。对于移动设备来说,避免这些不必要的资源浪费还是很重要的。我们来看一个简单的示例:

![responsive-web-design-content][14]

图中上半部分是大屏幕设备所显示的完整页面,下面的则是该页面在小屏幕设备的呈现方式。页面HTML代码如下:

    <p class="sidebar-nav"><a href="#">Left Sidebar Content</a> | <a href="#">Right Sidebar Content</a></p>
    
    
    <div id="content">
    
        <h2>Main Content</h2>
    
    </div>
    
    
    <div id="sidebar-left">
    
        <h2>A Left Sidebar</h2>
    
    
    </div>
    
    
    <div id="sidebar-right">
    
        <h2>A Right Sidebar</h2>
    
    </div>

下面是默认的主样式表,其中,我们要隐藏掉链接导航部分(sidebar-nav),因为默认样式适用的设备屏幕会足够大,足够显示包括两个侧边栏在内的所有内容。

#content{

    width: 54%;

    float: left;

    margin-right: 3%;

}


#sidebar-left{

    width: 20%;

    float: left;

    margin-right: 3%;

}


#sidebar-right{

    width: 20%;

    float: left;

}

.sidebar-nav{display: none;}

下面是用于小屏幕移动设备的样式表代码。现在,我们要隐藏掉两个侧边栏,并使sidebar-nav显示出来。借助JavaScript,当用户点击sidebar-nav中的链接时,对应的侧边栏可以恢复显示。当然,触发恢复显示的方式有很多种,即可以通过JS改变侧边栏的display属性值,也可以为其添加额外的布局样式。

#content{

    width: 100%;

}


#sidebar-left{

    display: none;

}


#sidebar-right{

    display: none;

}

.sidebar-nav{display: inline;}

现在,我们的页面已经可以随着设备和屏幕规格的变更,响应式的做到元素的同比缩放、布局结构的改变、内容的优化调整。特别是对于手机设备,我们还要在实践过程中注意一些该类设备共有的设计指导原则。比如,针对手机设备,使用一个特定的样式,将页面原有的文字导航元素变为更易操作的图标形式。下面的一些文章资源可作参考阅读:

Mobile Web Design Trends For 2009

7 Usability Guidelines for Websites on Mobile Devices

触屏与鼠标

触屏设备已经成为主流。虽然目前多数触屏设备还是小屏幕类型的产品,比如手机,但是市场上越来越多的大屏幕设备也开始使用触屏技术;且不说iPad一类的平板电脑,就连一些笔记本和台式机也加入了这一行列。比如HP Touchsmart tm2t,即使用传统的键鼠设备,同时也加入了触屏技术。

responsive-web-design-touchscreen

相比于传统的基于鼠标指针的互动,触屏技术显然带来了截然不同的交互方式与相应的设计规范;两者又有各自所适用的领域。所幸,要使我们的设计方案同时满足这两类设备的规范,并非一件难事,只是有些地方需要注意。比如,触屏设备无法反映CSS定义的hover行为及相应的样式,因为它没有鼠标指针的概念,手指点击就是click行为。所以不要让任何功能依赖于对hover状态的触发。

有兴趣的话,可以读读这篇"Designing for Touchscreen",这里提到的很多建议即有利于改进针对触屏设备的设计方式,同时也不会削弱传统键鼠设备上的用户体验。比如,放在页面右侧的导航列表可以对触屏设备的用户更加友好。因为多数人习惯用右手点击操作,而左手负责握住设备;这样,放在右侧的导航列表即方便右手的点击,又可以避免被握着设备的左手不小心触碰到。而这一点与键鼠设备用户的习惯完全不矛盾。

05月 27

现代浏览器中内置的几个可以等效替代jQuery的功能

jQuery的体积在不断的增大。新功能要不断增加,这是必然结果。虽然从版本1.8.3开始的瘦身效果明显,但不可否认的是,对于移动手机端的网页开发,它仍然是不可接受的。当然,jQuery不是铁板一块,你可以对它进行定制,只打包进你想要的组件,但其中的一些用来兼容老式浏览器的代码你无法去除。

就我的个人习惯来说,不管开发什么项目,即使是一个很简单的demo,我做的第一件事就是引入jQuery,这样做主要是想使用它提供的DOM选择器功能。对于一些像IE6/IE7这样的老式浏览器,这种做法是显而易见的,但是,如今现代浏览器里已经内置了完整的DOM选择器功能,能让你使用原生的浏览器提供的方法来实现jQuery的功能。

document.queryselector

这里说的现代浏览器是指火狐、谷歌、Opera、Safri等新生代浏览器,如果是IE,你需要至少是IE8或以上。你可以简单的将document.querySelector()函数映射为

$

,它能返回在DOM中找到的第一个匹配选择条件的元素。任何的CSS选择符都可以作为它的参数。

注意:IE 8只支持 CSS2.1标准的选择器

<div class="container"><br />  <ul><br />    <li id="pink">Pink</li><br />    <li id="salmon">Salmon</li><br /><br />    <li id="blue">Blue</li><br />    <li id="green">Green</li><br />    <li id="red">Red</li><br />  </ul>  <br /><br /></div><br /><br /><script><br /><br />  // 创建全局的 '$' 变量<br />  window.$ = function(selector) {<br />    return document.querySelector(selector);<br />  };<br /><br />  (function() {<br />    // 通过id查找item1,将它的背景颜色修改为浅红<br />    var item = $("#salmon").style.backgroundColor="salmon";<br />    console.log(item);<br />  }());  <br /></script>

你需要使用原生的“style”方法,而且这里不能使用jQuery里的链式调用。console.log()输出的将会是backgroundColor方法返回的“salmon”。

原生DOM节点有时候会比封装后的jQuery对象更好用。例如,如果你想修改一个图片的src属性,比较一下下面使用jQuery的做法和直接使用DOM节点的做法。

// jQuery方式<br />$("#picture").attr("src", "http://placekitten.com/200/200");<br /><br />//使用将querySelector映射为$的原生js方式<br />$("#picture").src = "http://placekitten.com/200/200";

DOM对象能让你直接访问图片的src属性,相反,所有的jQuery对象都需要你通过attr函数来操作。

document.querySelector方法只返回一个元素。如果你的选择目标是一堆元素,它只会返回符合条件的第一个节点。要想返回所有节点,你需要使用document.querySelectorAll方法。

document.queryselectorall

一个很巧妙的做法是将querySelector映射为$,而将querySelectorAll函数映射为$$。但它返回的是一个节点列表,不如jQuery里返回的Array格式好用,我们可以使用Array.prototype.slice.call(nodeList)方法加工一下,让它更方便。

<div class="container"><br />  <ul><br />    <li id="pink">Pink</li><br /><br />    <li id="salmon">Salmon</li><br /><br />    <li id="blue">Blue</li><br />    <li id="green">Green</li><br />    <li id="red">Red</li><br /><br />  </ul>  <br /><br /></div><br /><br /><script><br /><br />  window.$ = function(selector) {<br />    return document.querySelector(selector);<br />  };<br /><br />  window.$$ = function(selector) {<br />    var items = {},<br />    results = [],<br />    length = 0,<br />    i = 0;<br /><br />    // 注意,IE8不支持这种做法<br />    results = Array.prototype.slice.call(document.querySelectorAll(selector));<br /><br />    length = results.length;<br /><br />    // add the results to the items object<br />    for ( ; i < length; ) {<br />      items[i] = results[i];<br />      i++;<br />    }<br /><br />    // 添加一些额外的属性,让它更像一个Array<br />    items.length = length;<br />    items.splice = [].splice();<br /><br />    // 添加 'each' 方法<br />    items.each = function(callback) {<br />      var i = 0;<br />      for ( ; i < length; ) {<br />        callback.call(items[i]);<br />        i++;<br />      }<br />    }<br /><br />    return items;<br />  };<br /><br />  (function() {<br /><br />    // 查找green项,修改字体大小<br />    $("#green").style.fontSize = "2em";<br /><br />    // 通过id查找,修改背景色<br />    $$("li").each(function() {<br />      this.style.backgroundColor = this.id;<br />    });<br />  }());<br /><br /></script>

注意,IE8是不支持将一个nodeList转换为Array的。

classList

使用jQuery对CSS类操作十分方便,幸运的是,现代浏览器里也内置了一下方法能够很方便的操作它们,主要用到了classList对象。下面是一些基本操作两种方式的对比。

window.$ = function(selector) {<br />    return document.querySelector(selector);<br />  };<br /><br />  //----增加CSS类------<br /><br />  /* jQuery */<br />  $(".main-content").addClass("someClass");<br /><br />  /* 等效内置方法 */<br />  $(".main-content").classList.add("someClass");<br /><br />  //----删除一个CSS类-----<br /><br />  /* jQuery */<br />  $(".main-content").removeClass("someClass");<br /><br />  /* 等效内置方法 */<br />  $(".main-content").classList.remove("someClass");<br /><br />  //----判断是否存在一个CSS类---<br /><br />  /* jQuery */<br />  if($(".main-content").hasClass("someClass"))<br /><br />  /* 等效内置方法 */<br />  if($(".main-content").classList.contains("someClass"))

相对于jQuery提供大量丰富的方法,上面说的这几个现代浏览器里内置的功能显得很简单,但如果项目中的要求不高,这些替代方法能大大的减少你的应用依赖。

最后要提醒的是,这些内置方法在不同的浏览器和不同的版本中支持程度不一样,下面是它们的支持程度参考表。

附图1:各种浏览器对querySelector/querySelectorAll的兼容支持

各种浏览器对querySelector/querySelectorAll的兼容支持

附图1:各种浏览器对classlist的兼容支持

各种浏览器对classlist的兼容支持

03月 13

ExtJs使用总结

1.Ext.get
var el = Ext.get('myElementId');//获取元素,等同于document.getElementById('myElementId');//会缓存
2. Ext.fly
var el = Ext.fly('myElementId')//不需要缓存。
注:享元模式(Flyweight Design Pattern)是一种节省内存的模式,该模式的大概原理是建立单个全体对象然后不断反复使用它。
3.Ext.getDom
var elDom = Ext.getDom('elId'); // 依据id来查dom节点
var elDom1 = Ext.getDom(elDom); // 依据dom节点来查dom节点

二、CSS元素
4.addClass
Ext.fly('elId').addClass('myCls'); // 加入元素的'myCls'的样式
5.radioClass
Ext.fly('elId').radioClass('myCls');//添加一个或多个className到这个元素,并移除其所有侧边(siblings)节点上的同名样式。
6.removeClass
Ext.fly('elId').removeClass('myCls'); // 移除元素的样式
7.toggleClass
Ext.fly('elId').toggleClass('myCls'); // 加入样式
Ext.fly('elId').toggleClass('myCls'); // 移除样式
Ext.fly('elId').toggleClass('myCls'); // 再加入样式
8.hasClass
if (Ext.fly('elId').hasClass('myCls')) {//判断是否已加上这个样式
// 是有样式的……
}
10.replaceClass
Ext.fly('elId').replaceClass('myClsA', 'myClsB');//替换样式
11.getStyle
var color = Ext.fly('elId').getStyle('color');//返回该元素的统一化当前样式和计算样式。
var zIndx = Ext.fly('elId').getStyle('z-index');//返回该元素的统一化当前样式和计算样式。
12.setStyle
Ext.fly('elId').setStyle({
display : 'block',
overflow : 'hidden',
cursor : 'pointer'
});//设置元素的样式,也可以用一个对象参数包含多个样式。
13.getColor
Ext.fly('elId').getColor('color');//为指定的CSS属性返回CSS颜色
14.setOpacity

Ext.fly('elId').setOpacity(.45, true);//设置元素的透明度。
15.clearOpacity
Ext.fly('elId').clearOpacity();//清除这个元素的透明度设置

三、Dom游历
16.Ext.fly('elId').select('li:nth-child(2n)').addClass('red');
17.is 测试当前元素是否与传入的选择符相符一致。
复制代码代码如下:
var el = Ext.get('elId'); if (el.is('p.myCls')) { // 条件成立 }

18.findParent
定位于此节点,以此节点为起点,向外围搜索外层的父节点,搜索条件必须符合并匹配传入的简易选择符。
Ext.fly('elId').findParent('div'); // 返回dom节点
Ext.fly('elId').findParent('div', 4); // 查找4个节点
Ext.fly('elId').findParent('div', null, true); // 返回Ext.Element
19.findParentNode
定位于此节点的“父节点”,以此节点的“父节点”为起点,向外围搜索外层的“父父”节点,搜索条件必须符合并匹配传入的简易选择符。
Ext.fly('elId').findParentNode('div');
20.up
沿着DOM,向外围搜索外层的“父父”节点,搜索条件必须符合并匹配传入的简易选择符。
Ext.fly('elId').up('div');
Ext.fly('elId').up('div', 5); // 限5层的内查找
21.select
传入一个CSS选择符的参数,然后依据该CSS选择符从当前元素下面,形成期待匹配子节点的集合,也就是“选择”的操作,最后以一个Ext.CompositeElement类型的组合元素的形式返回。如果以Ext.select()调用表示从document可是搜索。
// 返回结果的CompositeElement
Ext.fly('elId').select('div:nth-child(2)');
// 返回数组
Ext.fly('elId').select('div:nth-child(2)',
true);
// 整个document都会搜索
Ext.select('div:nth-child(2)');
22.query
进行一次query的查询,返回DOM 节点组成的数组。可选地第二参数设置为查询的起点,如不指定则为 document。
// 返回dom节点组成的数组
Ext.query('div:nth-child(2)');
23.child
基于送入的选择符,不限定深度进行搜索,符合的话选取单个子节点。
Ext.fly('elId').child('p.highlight'); // 返回的类型是Ext.Element
Ext.fly('elId').child('p.highlight', true); // 返回dom节点
24.down
基于该选择符,"直接"选取单个子节点。
Ext.fly('elId').down('span'); // 返回的类型是Ext.Element
Ext.fly('elId').down('span', true); // 返回dom节点

25.parent
返回当前节点的那个父节点,可选地可送入一个期待的选择符。
// 返回父节点,类型是Ext.Element
Ext.fly('elId').parent();
// 返回父节点,类型是html dom
Ext.fly('elId').parent("", true);
// 返回父级节点,但一定要是div的,找到就返回,类型是Ext.Element
Ext.fly('elId').parent("div");
26.next
获取下一个侧边节点,跳过文本节点。可选地可送入一个期待的选择符。
// 返回下一个侧边节点,类型是Ext.Element
Ext.fly('elId').next();
// 返回下一个侧边节点,类型是html dom
Ext.fly('elId').next("", true);
// 返回下一个侧边节点,但一定要是div的,找到就返回,类型是Ext.Element
Ext.fly('elId').next("div");
27.prev
获取上一个侧边节点,跳过文本节点。可选地可送入一个期待的选择符。
// 返回上一个侧边节点,类型是Ext.Element
Ext.fly('elId').prev();
// 返回上一个侧边节点,类型是html dom
Ext.fly('elId').prev("", true);
// 返回上一个侧边节点,但一定要是div的,找到就返回,类型是Ext.Element
Ext.fly('elId').prev("div");
28.first
获取第一个侧边节点,跳过文本节点。可选地可送入一个期待的选择符。
// 返回第一个侧边节点,类型是Ext.Element
Ext.fly('elId').first();
// 返回第一个侧边节点,类型是html dom
Ext.fly('elId').first("", true);
// 返回第一个侧边节点,但一定要是div的,找到就返回,类型是Ext.Element
Ext.fly('elId').first("div");
29.last
获取最后一个侧边节点,跳过文本节点。可选地可送入一个期待的选择符。
// 返回最后一个侧边节点,类型是Ext.Element
Ext.fly('elId').last();
// 返回最后一个侧边节点,类型是html dom
Ext.fly('elId').last("", true);
// 返回最后一个侧边节点,但一定要是div的,找到就返回,类型是Ext.Element
Ext.fly('elId').last("div");

四、DOM操控(DHTML常见的一项任务就是DOM元素的增、删、改、查)
30.appendChild
把送入的元素归为这个元素的子元素。
var el = Ext.get('elId1');
// 用id指定
Ext.fly('elId').appendChild('elId2');
// Ext.Element添加
Ext.fly('elId').appendChild(el);
// 选择符组合地添加
Ext.fly('elId').appendChild(['elId2','elId3']);
// 直接添加dom节点
Ext.fly('elId').appendChild(el.dom);
// 添加CompositeElement,一组的div
Ext.fly('elId').appendChild(Ext.select('div'));
31.appendTo
把这个元素添加到送入的元素里面。
var el = Ext.get('elId1');
// 'elId'添加到'elId2'里面
Ext.fly('elId').appendTo('elId2');
Ext.fly('elId').appendTo(el); //
添加到Ext.Element el
32.insertBefore
传入一个元素的参数,将其放置在当前元素之前的位置。
var el = Ext.get('elId1');
// dom节点在前面插入
Ext.fly('elId').insertBefore('elId2');
//Ext.Element el在前面插入
Ext.fly('elId').insertBefore(el);
33.insertAfter
传入一个元素的参数,将其放置在当前元素之后的位置。
var el = Ext.get('elId1');
// dom节点在后面插入
Ext.fly('elId').insertAfter('elId2');
// Ext.Element el在后面插入
Ext.fly('elId').insertAfter(el);
34.insertFirst
可以是插入一个元素,也可以是创建一个元素(要创建的话请使用“DomHelper配置项对象”作为参数传入),总之,这个元素作为当前元素的第一个子元素出现。
var el = Ext.get('elId1');
// 插入的dom节点作为第一个元素
Ext.fly('elId').insertFirst('elId2');
// 插入的Ext.Element作为第一个元素
Ext.fly('elId').insertFirst(el);
// 用DomHelper配置项创建新节点,新节点会作为第一个子元素被插入。
Ext.fly('elId').insertFirst({
tag: 'p',
cls: 'myCls',
html: 'Hi I am the new first child'
});
35.replace
用于当前这个元素替换传入的元素。
var el = Ext.get('elId1');
// 'elId'去替换'elId2'
Ext.fly('elId').replace('elId2');
// 'elId'去替换'elId1'
Ext.fly('elId').replace(el);
36.replaceWith
用传入的元素替换这个元素。参数可以是新元素或是要创建的DomHelper配置项对象。
var el = Ext.get('elId1');
Ext.fly('elId').replaceWith('elId2'); // 'elId2'替换掉'elId'.
Ext.fly('elId').replaceWith(el); //
'elId1'替换掉'elId'
// 用DomHelper配置项创建新节点,并用该节点换掉‘elId'。
Ext.fly('elId').replaceWith({
tag: 'p',
cls: 'myCls',
html: 'Hi I have replaced elId'
});

五、DomHelper配置项
37.createChild
传入一个DomHelper配置项对象的参数,将其创建并加入到该元素。
var el = Ext.get('elId');
var dhConfig = {
tag: 'p',
cls: 'myCls',
html: 'Hi I have replaced elId'
};
// 创建新的节点,放到'elId'里面
el.createChild(dhConfig);
// 创建新的节点,居el第一个子元素之前
el.createChild(dhConfig, el.first());
38.wrap
创建一个新的元素,包裹在当前元素外面。
Ext.fly('elId').wrap(); // div包着elId
// 用新建的一个元素来包着elId
Ext.fly('elId').wrap({
tag: 'p',
cls: 'myCls',
html: 'Hi I have replaced elId'
});

六、Html片断
38.insertHtml
插入HTML片断到这个元素。至于要插入的html放在元素的哪里,你可指定beforeBegin, beforeEnd, afterBegin, afterEnd这几种。第二个参数是插入HTML片断,第三个参数是决定是否返回一个Ext.Element类型的DOM对象。
Ext.fly('elId').insertHtml(
'beforeBegin',
'

点击我

',
true
); // 返回Ext.Element
39.remove
从DOM里面移除当前元素,并从缓存中删除。.
Ext.fly('elId').remove(); //
elId在缓存和dom里面都没有
40.removeNode
移除document的DOM节点。如果是body节点的话会被忽略。
Ext.removeNode(node); // 从dom里面移除(HTMLElement)

七、Ajax
41.load
直接访问Updater的Ext.Updater.update()方法(相同的参数)。参数与Ext.Updater.update()方法的一致。
Ext.fly('elId').load({url: 'serverSide.php'})
42.getUpdater
获取这个元素的UpdateManager。
var updr = Ext.fly('elId').getUpdater();
updr.update({
url: 'http://myserver.com/index.php',
params: {
param1: "foo",
param2: "bar"
}
});

03月 04

你需要知道的三个CSS技巧

各种浏览器之间的竞争的白热化意味着越来越多的人现在开始使用那些支持最新、最先进的W3C Web标准的设备,以一种更具交互性的方式来访问互联网。这意味着我们终于能够利用更强大更灵活的CSS来创造更简洁,更好维护的浏览器前端代码。现在让我们来看一看一些也许你还不知道的让人兴奋的CSS 功能。


在CSS中用attr()显示HTML属性值


attr()功能早在CSS 2.1标准中就已经出现,但现在才开始普遍流行。它提供了一个巧妙的方法在CSS中使用HTML标签上的属性,在很多情况下都能帮你省去了以往需要Javascript处理的过程。

要想使用这个功能,你需要用到三种元素:一个:before:after CSS伪类样式, .content属性,和一个带有你想使用的HTML属性名称的attr()表达式。例如,想去显示<h3>标题上的data-prefix属性的值,你可以写成这样:

h3:before {
    content: attr(data-prefix) " ";
    }

    <h3 data-prefix="Custom prefix">This is a heading</h3>

显然,这个例子并没有展示它有多大用处,只是展示了它的基本用法。让我们来试一个更有用的例子,attr()的一个极好的应用就是当用户打印页面时将页面链接显示出来。为了实现这个,你可以这样写:

@media print {
    a:after {
    content: " (link to " attr(href) ") ";
    }
    }

    <a href="http://example.com">Visit our home page</a>

一旦你知道了这个技巧,你就会吃惊于很多时候它能给你的工作带来的方便!

提示:在新版的CSS3标准中,attr()功能被扩展,可以用在各种CSS标记中。


使用counter()在列表中自动添加序号


另外一个在CSS 2.1在就已经支持的功能是counter(),使用它,你能方便的在页面标题,区块和其它各种连续出现的页面内容上添加序号。有了它,你就不必限制于只能使用<ol>来实现这个效果,你可以更灵活的在页面上使用自定义数字序列。

关键就是它真的很简单:在:before伪类里的content属性加入counter():

body {
    counter-reset: heading;
    }

    h4:before {
    counter-increment: heading;
    content: "Heading #" counter(heading) "."; 
    }

如果你想知道更多关于这个counter归零和自增方法的知识,请参考关于这个主题的Mozilla
Developer Network
页面。里面有个极好的如何使用嵌套counter的例子。


使用calc()做算术


最后,但不是最不重要的,让我们来说说calc()功能。这个函数能让你执行简单的算术计算,例如计算元素的长宽,免去了你写不易维护的Javascript代码。这个函数支持所有简单的基本算术运算,包括加减乘除。

比方说,你想创建一个元素,使它的宽度占满它的父元素,但还要留出一部分像素宽做其它用处:

.parent {
    width: 100%;
    border: solid black 1px;
    position: relative;
    }

    .child {
    position: absolute;
    left: 100px;
    width: calc(90% - 100px);
    background-color: #ff8;
    text-align: center;
    }

漂亮吧,不是吗?更详细的介绍请参考W3C CSS calc 规范

我们可以越来越清楚的发现,CSS已经成熟到在某些方法可以替代javascript,极大的简化了web开发人员的工作。如果你还不开始利用这些功能,那只能说是在犯傻。


[英文原文:Three CSS features you need to know about

02月 06

jQuery Core 1.9 Upgrade Guide

以前预告过jQuery 1.9是最后一个支持IE6/7/8的版本,现在已经生米煮成熟饭了,jQuery 2.0起,将只支持IE 9+及其他HTML5浏览器。作为天朝这个特殊的国度的前端工程师就更加的苦逼了,同行们自重吧。jQuery 1.9 增加了一些新东西比如css3选择器等,删除和修改了一些API,升级后可能导致现有代码无法兼容,如果执意要升级jquery,做好改代码的准备吧~~~~
幸好jQuery团队提供了Migrate插件,用来检测弃用和已删除的API,或恢复原有的功能,对大部分API做了兼容,这样原来的程序大部分都可继续正常工作,But 作为一个牛逼的前端攻城狮,还是早点修改代码和习惯吧 
陈傻子英语水平实在是有限,无法准确的翻译官方的升级指南,各位看官还是Click下面的链接练鸟语吧^_^
01月 27

用户不愿注册的8个原因

对于大多数用户来说,网站注册是一个非常大的负担。用户注册你的网站等同于将自己的个人信息交给你并且信任你能够保护它的安全。如果你滥用他们的个人信息或侵犯了他们对你的信任,那你很容易失去你的用户。现在,许多用户都对他们提交的个人信息感到担忧,在处处隐藏着黑客和垃圾邮件满天飞的网络世界里,谁又能够制止他们的胡作非为呢?如果你的网站上用户注册登录数量不多的话,那说明你的网站还没得到用户的信任。以下列举的是用户不愿注册的8个原因:


1.害怕垃圾邮件


许多用户非常害怕在一个网站上注册后,接下来将会收到接连不断的垃圾邮件。这主要是因为在注册的时候,用户需要留下他的邮箱地址。如果你确定需要用户留下邮箱,那就请在邮箱地址输入框旁边注明这个邮箱地址的用处。这样可以减轻用户对垃圾邮件的恐惧,使他们给你电子邮件时会舒服一点儿。

 


2. 担心类似Facebook/Twitter的关联注册后,会向他的朋友和粉丝发送垃圾信息


用户都很反感垃圾消息,他们也不希望自己的朋友收到这样的垃圾消息,更何况是来自他们发送的。众所周之,使用Facebook/Twitter的关联注册后,都会自动默认给他的粉丝和朋友一条更新动态。如果你打算使用Facebook/Twitter的关联注册,务必要让用户知道你的应用程序将不会自动向平台上推送任何更新的动态。

 


3. 无法注销帐户


有时用户在注册网站后,最终不再想使用它。此时允许用户注销账户,会使那些不愿意在网站上留下他们上网痕迹的用户感到心安。让用户知道,在你的网站上注册后,他们随时可以将账户注销。只有这样用户才不担心他们的个人信息会被永远的保留在你的网站上。

 


4. 对提交的个人信息缺乏安全感


如果用户要给你提交高度敏感的信息,比如信用卡号码或者家庭地址,他们很想知道你的网站是如何安全的处理那些信息的。这需要你在服务器上加密存储他们的信息,以防你的网站被黑客攻击,更或者是落入坏人之手。这就要提示用户让用户知道他们的信息是通过加密后安全的存储在你的服务器上。

 


5. 需要填入的信息选项过多


如果需要输入的信息太多,那么用户就会权衡从你网站能够得到的是否值得他们这么去做?如果不值得,那么他们也没耐心继续注册下去。但是如用认为这样做值得,为了从网站获取想要的东西,他们将不遗余力。一般原则是少让用户在注册时填写更多信息,只有这样才不致让用户反感,一旦用户在网站注册了,总会有更多机会来获取你想要的信息。

 


6. 让用户填写他们认为不必要的信息


让用户填写的每一项信息都应与网站服务相关。如果让用户感觉到填写的信息没必要,他们不是给你假信息,就是不去填写。如果有必填信息但又很容易让用户疑虑是否有必要时,可以在输入框旁解释一下要填写的原因。

 


7. 免费试用的时候向用户索要信用卡号码


在网站还没得到用户认可之前,提供免费试用机会让用户尝试体验你的网站是否是他们所需要的,是一种常用的做法。但免费试用时就让用户填入信用卡号码,很容易让用户感觉到这有很大的安全风险。即使你不在免费试用阶段强迫他们付费,但总是有很多用户仍会觉得让人不安。所以,在用户体验免费试用时,最好不要让他们填写信用卡信息,但如果他们在体验过程中想要更好的服务,就提醒他们去购买。

 


8. 产品/服务不清晰或者不吸引人


当用户访问你的首页时,他们都很想知道你的网站是做什么的。如果网站让用户搞不清楚它的主营业务,那你的首页就需要改改了。让用户不明白网站是做什么或是这个网站不够吸引,那他们不会注册的。只有网站的定位、业务展现清晰,让访问者知道价值所在,才能到吸引他们。

 


总之,这全都可归结于让用户信任和舒适


让用户注册的全都在乎于他们的信任和舒适感。要让用户知道他们提交的信息是受保护的,让他们清楚你要这些敏感信息的用途,只有这要才能取得用户的信任。只有让用户决定自己的信息以及在注册时减少不必要的填写项,才能让用户感到舒适。如果你能按着以上这几点去做,用户是没有理由不在你网站注册的。

  Via:uxmovement