前端技术 ’ 目录归档

[翻译]Jade模板引擎中文API,适合入门

Jade是一款高性能简洁易懂的模板引擎,Jade是Haml的Javascript实现,在服务端(NodeJS)及客户端均有支持。

功能
客户端支持
超强的可读性
灵活易用的缩进
块扩展
代码默认经过编码处理以增强安全性
编译及运行时的上下文错误报告
命令行编译支持
HTML5模式(使用!!!5文档类型)
可选的内存缓存
联合动态和静态标记类
利用过滤器解析树的处理
支持 Express JS
利用each透明的循环objects,arrays甚至不可枚举对象
块注释
不需要标记前缀
AST过滤器
过滤器
:sass 需要安装sass.js
:less 需要安装less.js
:markdown 需要安装markdown-js或node-discount
:cdata
:coffeescript 需要安装coffee-script
Vim语法文件
TextMate包
Screencasts
其它语言实现
php
Scala
Ruby
安装
通过npm:

npm install jade

浏览器支持
可以通过下面命令将jade编译为客户端浏览器兼容的文件:

$ make jade.js

或者,如果你已经通过npm安装了uglifyjs(npminstalluglify-js),可以通过下面的命令同时创建两个文件:

$ make jade.min.js

公开API

var jade = require('jade');
 
// 渲染字符串
jade.render('.saecn.com 字符串', { options: 'here' });
 
// 渲染文件
jade.renderFile('path/to/saecn.com.jade', { options: 'here' }, function(err, html){
   // 这里的options是可选的
   // 回调函数可以作为第二个参数
});
 
// 编译一个函数
var fn = jade.compile('string of jade', options);
fn.call(scope, locals);

Options

执行作用域(this)scope
本地变量对象locals
处理异常及缓存时使用filename
通过文件名将Javascript缓存在内存中cache
输出生成的标记和函数体debug
替换jade默认编译引擎compiler
语法
行尾

在解析前会将 CRLF 和 CR 转换为 LF.

标记

标记是一行的第一个单词:

html

会被转换为 <html></html>

标记也可以有id:

div#container

这将被渲染成

<div id=”container”></div>

如何处理类?

div.user-details

渲染为: <div class=”user-details”></div>

多个class?并且还有id?

div#foo.bar.baz

渲染为:<div id=”foo” class=”bar baz”></div>

总写div确实很烦人,可以省略之:

#foo
.bar

输出: <div id=”foo”></div><div class=”bar”></div>

标记文本

只需要将文本内容放在标记后面:

p wahoo!

渲染为

<p>wahoo!</p>

.

酷,但是如何处理大段文本呢?

p
| foo bar baz
| rawr rawr
| super cool
| go jade go

渲染为

<p>foo bar baz rawr…..</p>

内插法?是的,这两种类型的文本都可以使用内插法,如果我们传入{ locals: { name: ‘一回’, email: ‘xianlihua[at]gmail.com’ }},可以这样做:

#user #{name} <#{email}>

输出:

<div id=”user”>一回 &lt;saecn[at]gmail.com&gt;</div>

出于某种原因需要输出#{}?转义之:

p \#{Saecn, 关注Javascript技术}

这样就得到了:

<p>#{Saecn, 关注Javascript技术}</p>

也可以使用反转义变量!{html},下面的代码将输出script标记:

– var html = “
| !{html}

包含文本的嵌套标记也可以使用文本块:

label
| Username:
input(name=’user[name]’)

或者直接使用标记文本:

label Username:
input(name=’user[name]’)

只接受纯文本的标记,如script,style,以及textarea不需要开头的|字符,例如:

html
head
title Saecn, 关注Web前端技术
script
if (foo) {
bar();
} else {
baz();
}

再次作为替代方案,我们可以使用点号’.’来表示一个文本块,例如:

p.
foo asdf
asdf
asdfasdfaf
asdf
asd.

输出:

   <p>foo asdf
    asdf
      asdfasdfaf
      asdf
    asd
    .
    </p>

如果点号’.’与标记之间有空格,Jade解析其会忽略它,将其作为文本处理:

p .

输出:

<p>.</p>

注释

单行注释当前看起来与Javascript一致,即“//”,单行注释的内容必须放在同一行上:

// 一些段落
p foo
p bar

将会输出:

<!– 一些段落 –>
<p>foo</p>
<p>bar</p>

Jade也支持非缓冲注释,只需增加一个横杠:

//- 该行注释将不会被输出到解析后的页面中
p foo
p bar

输出:

foo

<p>bar</p>

块注释

块注释会依据缩进进行处理:

body
//
#content
h1 Saecn,关注Web前端技术

输出:

<body>
<!–
<div id=”content”>
<h1>Saecn,关注Web前端技术</h1>
</div>
–>
</body>

Jade也支持条件注释,例如:

body
/if IE
a(href=’http://www.mozilla.com/en-US/firefox/’) Get Firefox

输出:

<body>
<!–[if IE]>
<a href=”http://www.mozilla.com/en-US/firefox/”>Get Firefox</a>
<![endif]–>
</body>

嵌套

Jade支持通过嵌套来以自然的方式定义标记:

ul
li.first
a(href=’#’) foo
li
a(href=’#’) bar
li.last
a(href=’#’) baz

块扩展

块扩展允许创建单行的简洁嵌套标记,下面的示例与上例输出相同:

ul
li.first: a(href=’#’) foo
li: a(href=’#’) bar
li.last: a(href=’#’) baz

特性

目前Jade支持’(‘和’)’的特性定界符。

a(href=’/login’, title=’View login page’) Login

另外我们也可以使用冒号(:)来作为分割符:

a(href: ‘/login’, title: ‘注册成为Saecn.com会员’) Login

Boolean特性也被支持:

input(type=”checkbox”, checked)

值为变量的Boolean特性只有在值为true时输出:

input(type=”checkbox”, checked: someValue)

分拆在多行也能正常解析:

input(type=’checkbox’,
name=’agreement’,
checked)

文档类型

利用!!!来增加页面的文档类型:

!!!

将会输出过渡型文档类型,然而:

!!! 5

将会输出HTML5的文档类型,下面是默认定义的文档类型,这也可以很容易的被扩展:

var doctypes = exports.doctypes = {
‘5’: ‘‘,
‘xml’: ‘‘,
‘default’: ‘‘,
‘transitional’: ‘‘,
‘strict’: ‘‘,
‘frameset’: ‘‘,
‘1.1’: ‘‘,
‘basic’: ‘‘,
‘mobile’: ‘‘
};

要修改默认值只需改变:

jade.doctypes.default = ‘whatever you want’;

过滤器
过滤器以冒号(:)作为前缀,如 :markdown 将会对文本进行函数处理,(一回注:类似Smarty的变量调节器),本页开始处列出了目前Jade支持的过滤器。

body
:markdown
Woah! jade _and_ markdown, very **cool**
we can even link to [Saecn](http://www.saecn.com)

渲染后:

<body><p>Woah! jade <em>and</em> markdown, very <strong>cool</strong> we can even link to <a href="http://www.saecn.com">Saecn</a></p></body>

过滤器也可以处理解析树,通常过滤器可以正常处理文本块,但是通过传入规则的块过滤器可以做任何它能做的。

body
conditionals:
if role == ‘admin’
p You are amazing
else
p Not so amazing

代码
Jade目前支持三种类型的可执行代码,第一种以-为前缀,不会被缓冲:

– var foo = ‘bar’;

这可被用于条件或循环:

– for (var key in obj)
p= obj[key]

由于Jade的缓冲技术,下面的代码是有效的:

– if (foo)
ul
li yay
li foo
li worked
– else
p oh no! you are not in saecn.com

甚至详细的迭代循环:

– if (items.length)
ul
– items.forEach(function(item){
li= item
– })

任何你希望的都可以实现!

接下来我们转义了缓冲代码,用于缓冲返回值,以等号(=)作为前缀:

– var foo = ‘bar’
= foo
h1= foo

输出: bar

bar

. 被’=’缓冲的代码会默认经过转义以增强安全性,要输出为转义的值需要使用 !=:

p!= aVarContainingMoreHTML

一个允许使用”vanilla”Javascript的例外,是 – each 标记,其表现形式为:

– each VAL[, KEY] in OBJ

实现循环数组的例子:

– var items = [“one”, “two”, “three”]
– each item in items
li= item

输出:

<li>one</li>
<li>two</li>
<li>three</li>

循环对象的键和值:

– var obj = { foo: ‘bar’ }
– each val, key in obj
li #{key}: #{val}

这会输出 <li>foo: bar</li>

也可以进行嵌套循环:

– each user in users
– each role in user.roles
li= role

当一个属性为undefined,Jade会输出空串,例如:

textarea= user.signature

近期的Jade版本会输出空字符串而不是undefined:

<textarea></textarea>

命令行工具:bin/jade
输出html到标准输出(stdout):

jade examples/*.jade --pipe

生成 examples/*.html :

jade examples/*.jade

传入参数:

jade examples/layout.jade --options '{ locals: { title: "Saecn" }}'

[扫盲]css中使用的中文转化码

是不是在CSS文件中定义个性中文字体而烦恼呢?现在就告诉你一个方法吧!

有一种快速获得字体 Unicode 编码的方法,如果你使用火狐的 Firebug 插件,直接在控制台中输入 escape(‘黑体’),就可以得到黑体的 Unicode 编码,但需要经过处理才可以使用到 CSS 文件中来,请看下图所示:

201103171204317592

于此获得到了 “%u9ED1%u4F53″,将其改写为 “\9ED1\4F53″ 即可写入 CSS 文件。

这样或许还是有些小麻烦,那也没关系,芒果这里有一份比较完整的表格,自己查吧。

中文名 Unicode
新细明体 \65B0\7EC6\660E\4F53
细明体 \7EC6\660E\4F53
标楷体 \6807\6977\4F53
黑体 \9ED1\4F53
宋体 \5B8B\4F53
新宋体 \65B0\5B8B\4F53
仿宋 \4EFF\5B8B
楷体 \6977\4F53
仿宋_GB2312 \4EFF\5B8B_GB2312
楷体_GB2312 \6977\4F53_GB2312
微软正黑体 \5FAE\x8F6F\6B63\9ED1\4F53
微软雅黑 \5FAE\8F6F\96C5\9ED1

原文转自:http://appwycom.w08.ivip.cn/?p=316

基于jQuery的五子棋等多子棋游戏插件

今天早上一来呢就将多子棋插件版本更新到V0.1.1,主要原因是昨晚回家完了一下,发现这个游戏在某种特定的情况下会失去判断输赢的情况,接下来就列一下这个插件的详细信息:

/******************************************
* 多子棋插件
*
* @作者 :听涛设计
* @版权 :Copyright (c) 2013 听涛TinTao.
* @网址 :http://www.saecn.com
* @更新 : 2013-05-08
* @版本 :Version 0.1.1
*
******************************************/

主要功能:

1.可以实现多子棋游戏效果;

2.可以自由设定多少棋子连成串可以赢;

3.可以设置游戏画布的宽高;

游戏源码已经更新到GitHub:https://github.com/jactorew/wzGame

DEMO可以移步:jQuery五子棋游戏

欢迎大家多多指正多提意见。

游戏缺点:

UI素材来自互联网,没有独立的CSS样式文件,对于修改皮肤比较困难。

教你在Seajs中如何使用Jquery和Jquery的插件

最近了解到seajs的模块化js开发不错,拿来一看,呵呵,傻眼了。seajs做原生javascript开发还不错,就是像我这样的jquery控木有办法了。在细心翻阅了seajs官方文档后发现,原来seajs提供有配置jquery的方法,于是乎博主就开始照着文档开始配置,结果是文件下载下来了,但是全部报错,咋个回事呢???代码如下:

seajs.config({
plugins: ['shim'],

alias: {
'jquery': {
src: './lib/jquery.1.8.2.min.js',
exports:'jQuery'
},

'jquery.ui.core': {
src: './lib/jquery.ui/jquery.ui.core.min.js',
deps: ['jquery']
}
}
});

看起来不应该是这里的问题,完全按照官方文档写的啊! 纠结了半天查阅了无数资料后,终于发现另一种在seajs中使用jquery和jquery插件的方法:

var $ = require('jquery');
require('./lib/jquery.ui/jquery.ui.core.min')($);

这个方法必须将所有的jquery和插件重新封装一次

define(function(require,exports,moudles){
return function(jQuery){
(function(){/*code*/})(jQuery);
}

})

这下就完美解决了,不过这种方法加载的jquery和插件只能在这个文件内部使用,相当于局部变量,页面和其他无依赖的js不能使用,好处是插件与框架间无干扰。

[收藏]Javascript循环元素并绑定事件

废话不多说,直接上代码!具体原理请参考JS闭包原理

<!DOCTYPE html PUBLIC ”-//W3C//DTD XHTML 1.0 Transitional//EN” ”http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=“http://www.w3.org/1999/xhtml” >
<head>
<title>Untitled Page</title>
</head>
<body>
<ul id=“list”>
<li>第1条记录</li>
<li>第2条记录</li>
<li>第3条记录</li>
<li>第4条记录</li>
<li>第5条记录</li>
<li>第6条记录</li>
</ul>

<script type=“text/javascript”>
var list_obj = document.getElementById(“list”).getElementsByTagName(“li”); //获取list下面的所有li的对象数组
for (var i = 0; i <= list_obj.length; i++) {
(function(){
var p = i
list_obj[i].onmousemove = function() {
this.style.backgroundColor = “#cdcdcd”;
}
list_obj[i].onmouseout = function() {
this.style.backgroundColor = “#FFFFFF”;
}
list_obj[i].onclick = function() {
alert(“这是第” + p + “记录”);
}
})()
}
</script>

</body>
</html>

[收藏]学习Javascript闭包(Closure)

写在前面的话:闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

 

一、变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

var n=999;

function f1(){
alert(n);
}

f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

function f1(){
var n=999;
}

alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

function f1(){
n=999;
}

f1();

alert(n); // 999

二、如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数。

function f1(){

var n=999;

function f2(){
alert(n); // 999
}

}

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

function f1(){

var n=999;

function f2(){
alert(n);
}

return f2;

}

var result=f1();

result(); // 999

三、闭包的概念

上一节代码中的f2函数,就是闭包。

各种专业文献上的”闭包”(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

四、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

怎么来理解这句话呢?请看下面的代码。

function f1(){

var n=999;

nAdd=function(){n+=1}

function f2(){
alert(n);
}

return f2;

}

var result=f1();

result(); // 999

nAdd();

result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是”nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、思考题

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

代码片段一。

var name = "The Window";

var object = {
name : "My Object",

getNameFunc : function(){
return function(){
return this.name;
};

}

};

alert(object.getNameFunc()());

代码片段二。

var name = "The Window";

var object = {
name : "My Object",

getNameFunc : function(){
var that = this;
return function(){
return that.name;
};

}

};

alert(object.getNameFunc()());

(完)

[收藏]IE和Firefox的Javascript兼容性总结

长久以来JavaScript兼容性一直是Web开发者的一个主要问题。在正式规范、事实标准以及各种实现之间的存在的差异让许多开发者日夜煎熬。为此,主要从以下几方面差异总结IE和Firefox的Javascript兼容性:

一、函数和方法差异

二、样式访问和设置

三、DOM方法及对象引用

四、事件处理

五、其他差异的兼容处理

 

一、函数和方法差异

1. getYear()方法

【分析说明】先看一下以下代码:

var year= new Date().getYear();
document.write(year);

在IE中得到的日期是”2010″,在Firefox中看到的日期是”110″,主要是因为在 Firefox 里面 getYear 返回的是 “当前年份-1900” 的值。

【兼容处理】

加上对年份的判断,如:

var year= new Date().getYear();
year = (year&lt;1900?(1900+year):year);
document.write(year);

也可以通过 getFullYear getUTCFullYear 去调用:

var year = new Date().getFullYear();
document.write(year);

2. eval()函数

【分析说明】在IE中,可以使用eval(“idName”)或getElementById(“idName”)来取得id为idName的HTML对象;Firefox下只能使用getElementById(“idName”)来取得id为idName的HTML对象。

【兼容处理】统一用getElementById(“idName”)来取得id为idName的HTML对象。

 

3. const声明

【分析说明】在 IE 中不能使用 const 关键字。如:

const constVar = 32;

在IE中这是语法错误。

【兼容处理】不使用 const ,以 var 代替。

 

4. var

【分析说明】请看以下代码:

echo=function(str){
document.write(str);
}

这个函数在IE上运行正常,Firefox下却报错了。

【兼容处理】而在echo前加上var就正常了,这个就是我们提到var的目的。

 

5. const 问题

【分析说明】在 IE 中不能使用 const 关键字。如 const constVar = 32; 在IE中这是语法错误。

【解决方法】不使用 const ,以 var 代替。

 

二、样式访问和设置

1. CSS的”float”属性

【分析说明】Javascript访问一个给定CSS 值的最基本句法是:object.style.property,但部分CSS属性跟Javascript中的保留字命名相同,如”float”,”for”,”class”等,不同浏览器写法不同。

在IE中这样写:

document.getElementById("header").style.styleFloat = "left";

在Firefox中这样写:

document.getElementById("header").style.cssFloat = "left";

【兼容处理】在写之前加一个判断,判断浏览器是否是IE:

if(document.all){
  document.getElementById("header").style.styleFloat = "left";
}
else{
  document.getElementById("header").style.cssFloat = "left";
}

 

2. 访问<label>标签中的”for”

【分析说明】和”float”属性一样,同样需要使用不现的句法区分来访问<label>标签中的”for”。

在IE中这样写:

var myObject = document.getElementById("myLabel");
var myAttribute = myObject.getAttribute("htmlFor");

在Firefox中这样写:

var myObject = document.getElementById("myLabel");
var myAttribute = myObject.getAttribute("for");

【兼容处理】解决的方法也是先 判断浏览器类型。

 

3. 访问和设置class属性

【分析说明】同样由于class是Javascript保留字的原因,这两种浏览器使用不同的 JavaScript 方法来获取这个属性。

IE8.0之前的所有IE版本的写法:

var myObject = document.getElementById("header");
var myAttribute = myObject.getAttribute("className");

适用于IE8.0 以及 firefox的写法:

var myObject = document.getElementById("header");
var myAttribute = myObject.getAttribute("class");

另外,在使用setAttribute()设置Class属性的时候,两种浏览器也存在同样的差异。

setAttribute("className",value);

这种写法适用于IE8.0之前的所有IE版本,注意:IE8.0也不支持”className”属性了。

setAttribute(“class”,value);适用于IE8.0 以及 firefox。

【兼容处理】

方法一,两种都写上:

var myObject = document.getElementById("header");
myObject.setAttribute("class","classValue");
myObject.setAttribute("className","classValue");
 //设置header的class为classValue

方法二,IE和FF都支持object.className,所以可以这样写:

var myObject = document.getElementById("header");
myObject.className="classValue";//设置header的class为classValue

方法三,先判断浏览器类型,再根据浏览器类型采用对应的写法。

 

4. 对象宽高赋值问题

【分析说明】FireFox中类似 obj.style.height = imgObj.height 的语句无效。

【兼容处理】统一使用 obj.style.height = imgObj.height + ‘px’;

 

三、DOM方法及对象引用

1. getElementById

【分析说明】先来看一组代码:

<!– input对象访问1 –>
<input id=”id” type=”button”
value=”click me” ōnclick=”alert(id.value)”/>

在Firefox中,按钮没反应,在IE中,就可以,因为对于IE来说,一个HTML 元素的 ID 可以直接在脚本中当作变量名来使用,而Firefox中不可以。

【兼容处理】尽量采用W3C DOM 的写法,访问对象的时候,用document.getElementById(“id”) 以ID来访问对象,且一个ID在页面中必须是唯一的,同样在以标签名来访问对象的时候,用document.getElementsByTagName(“div”)[0] 。该方式得到较多浏览器的支持。

<!– input对象访问2 –>
<input id=”id” type=”button” value=”click me”
  onclick=”alert(document.getElementById(‘id’).value)” />

 

2. 集合类对象访问

【分析说明】IE下,可以使用()或[]获取集合类对象;Firefox下,只能使用[]获取集合类对象。如:

document.write(document.forms("formName").src);
//该写法在IE下能访问到Form对象的scrc属性

【兼容处理】将document.forms(“formName”)改为 document.forms[“formName”]。统一使用[]获取集合类对象。

 

3. frame的引用

【分析说明】IE可以通过id或者name访问这个frame对应的window对象,而Firefox只可以通过name来访问这个frame对应的window对象。

例如如果上述frame标签写在最上层的window里面的htm里面,那么可以这样访问:

IE: window.top.frameId或者window.top.frameName来访问这个window对象;

Firefox:只能这样window.top.frameName来访问这个window对象。

【兼容处理】使用frame的name来访问frame对象,另外,在IE和Firefox中都可以使用window.document.getElementById(”frameId”)来访问这个frame对象。

 

4. parentElement

【分析说明】IE中支持使用parentElement和parentNode获取父节点。而Firefox只可以使用parentNode。

【兼容处理】因为firefox与IE都支持DOM,因此统一使用parentNode来访问父节点。

 

5. table操作

【分析说明】IE下table中无论是用innerHTML还是appendChild插入<tr>都没有效果,而其他浏览器却显示正常。

【兼容处理】解决的方法是,将<tr>加到table的<tbody>元素中,如下面所示:

var row = document.createElement("tr");
var cell = document.createElement("td");
var cell_text = document.createTextNode("插入的内容");
cell.appendChild(cell_text);
row.appendChild(cell);
document.getElementsByTagName("tbody")[0].appendChild(row);

 

6. 移除节点removeNode()和removeChild()

【分析说明】appendNode在IE和Firefox下都能正常使用,但是removeNode只能在IE下用。

removeNode方法的功能是删除一个节点,语法为node.removeNode(false)或者node.removeNode(true),返回值是被删除的节点。

removeNode(false)表示仅仅删除指定节点,然后这个节点的原孩子节点提升为原双亲节点的孩子节点。

removeNode(true)表示删除指定节点及其所有下属节点。被删除的节点成为了孤立节点,不再具有有孩子节点和双亲节点。

【兼容处理】Firefox中节点没有removeNode方法,只能用removeChild方法代替,先回到父节点,在从父节点上移除要移除的节点。

node.parentNode.removeChild(node);</div>
// 为了在ie和firefox下都能正常使用,取上一层的父结点,然后remove。

 

7. childNodes获取的节点

【分析说明】childNodes的下标的含义在IE和Firefox中不同,看一下下面的代码:

<ul id=”main”>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<input type=button value=”click me!” onclick=
“alert(document.getElementById(‘main’).childNodes.length)”>

分别用IE和Firefox运行,IE的结果是3,而Firefox则是7。Firefox使用DOM规范,”#text”表示文本(实际是无意义的空格和换行等)在Firefox里也会被解析成一个节点,在IE里只有有实际意义的文本才会解析成”#text”。

【兼容处理】

方法一,获取子节点时,可以通过node.getElementsByTagName()来回避这个问题。但是 getElementsByTagName对复杂的DOM结构遍历明显不如用childNodes,因为childNodes能更好的处理DOM的层次结构。

方法二,在实际运用中,Firefox在遍历子节点时,不妨在for循环里加上:

if(childNode.nodeName==”#text”) continue;//或者使用nodeType == 1。

这样可以跳过一些文本节点。

延伸阅读

IE和FireFox中的childNodes区别

 

8. Firefox不能对innerText支持

【分析说明】Firefox不支持innerText,它支持textContent来实现innerText,不过textContent没有像innerText一样考虑元素的display方式,所以不完全与IE兼容。如果不用textContent,字符串里面不包含HTML代码也可以用innerHTML代替。也可以用js写个方法实现,可参考《为firefox实现innerText属性》一文。

【兼容处理】通过判断浏览器类型来兼容:

if(document.all){
document.getElementById('element').innerText = "my text";
} else{
document.getElementById('element').textContent = "my text";
}

 

四、事件处理

如果在使用javascript的时候涉及到event处理,就需要知道event在不同的浏览器中的差异,主要的JavaScript的事件模型有三种(参考《Supporting Three Event Models at Once》),它们分别是NN4、IE4+和W3C/Safar。

 

1. window.event

【分析说明】先看一段代码

function et()
{
alert(event);//IE: [object]
}

以上代码在IE运行的结果是[object],而在Firefox无法运行。

因为在IE中event作为window对象的一个属性可以直接使用,但是在Firefox中却使用了W3C的模型,它是通过传参的方法来传播事件的,也就是说你需要为你的函数提供一个事件响应的接口。

【兼容处理】添加对event判断,根据浏览器的不同来得到正确的event:

function et()
{
    evt=evt?evt:(window.event?window.event:null);
   //兼容IE和Firefox
    alert(evt);
}

 

2. 键盘值的取得

【分析说明】IE和Firefox获取键盘值的方法不同,可以理解,Firefox下的event.which与IE下的event.keyCode相当。关于彼此不同,可参考《键盘事件中keyCode、which和charCode 的兼容性测试

【兼容处理】

function myKeyPress(evt){
//兼容IE和Firefox获得keyBoardEvent对象
evt = (evt) ? evt : ((window.event) ? window.event : "")
//兼容IE和Firefox获得keyBoardEvent对象的键值
var key = evt.keyCode?evt.keyCode:evt.which;
if(evt.ctrlKey &amp;&amp; (key == 13 || key == 10)){
       //同时按下了Ctrl和回车键
//do something;
}
}

 

3. 事件源的获取

【分析说明】在使用事件委托的时候,通过事件源获取来判断事件到底来自哪个元素,但是,在IE下,event对象有srcElement属性,但是没有target属性;Firefox下,even对象有target属性,但是没有srcElement属性。

【兼容处理】

ele=function(evt){ //捕获当前事件作用的对象
evt=evt||window.event;
return (obj=event.srcElement?event.srcElement:event.target;);
}

 

4. 事件监听

【分析说明】在事件监听处理方面,IE提供了attachEvent和detachEvent两个接口,而Firefox提供的是addEventListener和removeEventListener。

【兼容处理】最简单的兼容性处理就是封装这两套接口:

function addEvent(elem, eventName, handler) {
if (elem.attachEvent) {
elem.attachEvent("on" + eventName, function(){
    handler.call(elem)});
    //此处使用回调函数call(),让this指向elem
} else if (elem.addEventListener) {
    elem.addEventListener(eventName, handler, false);
}
}
function removeEvent(elem, eventName, handler) {
if (elem.detachEvent) {
elem.detachEvent("on" + eventName, function(){
    handler.call(elem)});
    //此处使用回调函数call(),让this指向elem
} else if (elem.removeEventListener) {
elem.removeEventListener(eventName, handler, false);
}
}

需要特别注意,Firefox下,事件处理函数中的this指向被监听元素本身,而在IE下则不然,可使用回调函数call,让当前上下文指向监听的元素。

 

5. 鼠标位置

【分析说明】IE下,even对象有x,y属性,但是没有pageX,pageY属性;Firefox下,even对象有pageX,pageY属性,但是没有x,y属性。

【兼容处理】使用mX(mX = event.x ? event.x : event.pageX;)来代替IE下的event.x或者Firefox下的event.pageX。复杂点还要考虑绝对位置。

function getAbsPoint(e){
var x = e.offsetLeft, y = e.offsetTop;
while (e = e.offsetParent) {
x += e.offsetLeft;
y += e.offsetTop;
}
alert("x:" + x + "," + "y:" + y);
}
五、其他差异的兼容处理

1. XMLHttpRequest

【分析说明】new ActiveXObject(“Microsoft.XMLHTTP”);只在IE中起作用,Firefox不支持,但支持XMLHttpRequest。

【兼容处理】

 

function createXHR() {
var xhr=null;
if(window.XMLHttpRequest){
xhr=new ActiveXObject("Msxml2.XMLHTTP");
}else{
try {
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
catch() {
xhr=null;
}
}
if(!xhr)return;
return xhr;
}

 

2. 模态和非模态窗口

【分析说明】IE中可以通过showModalDialog和showModelessDialog打开模态和非模态窗口,但是Firefox不支持。

【解决办法】直接使用window.open(pageURL,name,parameters)方式打开新窗口。 如果需要传递参数,可以使用frame或者iframe。

 

3. input.type属性问题

 

IE下 input.type属性为只读,但是Firefox下可以修改

 

4. 对select元素的option操作

设置options,IE和Firefox写法不同:

Firefox:可直接设置

option.text = ‘foooooooo’;

IE:只能设置

option.innerHTML = ‘fooooooo’;

删除一个select的option的方法:

Firefox:可以

select.options.remove(selectedIndex);

IE7:可以用

select.options[i] = null;

IE6:需要写

select.options[i].outerHTML = null;

 

5. img对象alt和title的解析

【分析说明】img对象有alt和title两个属性,区别在于,alt:当照片不存在或者load错误时的提示。

title:照片的tip说明, 在IE中如果没有定义title,alt也可以作为img的tip使用,但是在Firefox中,两者完全按照标准中的定义使用

在定义img对象时。

【兼容处理】最好将alt和title对象都写全,保证在各种浏览器中都能正常使用 。

 

6. img的src刷新问题

【分析说明】先看一下代码:

<img id=”pic” onclick= “this.src= ‘a.jpg'”
  src=”aa.jpg” style=”cursor: pointer”/>

在IE 下,这段代码可以用来刷新图片,但在FireFox下不行。主要是缓存问题。

【兼容处理】在地址后面加个随机数就解决了:

<img id=”pic” onclick= “javascript:this.src=this.src+’?’
     +Math.random()”src=”a.jpg” style=”cursor: pointer”/>

 

总结

IE和Firefox的Javascript方面存在着不少的差异,要做到兼容,我觉得很有必要把一些常见的整理成一个js库,如DOM的操作,事件的处理,XMLHttpRequest请求等,或者也可以选择使用现有的一些库(如jQuery,YUI,ExtJs等),不过我觉得还是有必要了解一下这些差异,这样对于我们参加兼容性和可用性代码很有帮助。

办法总比问题多,无论浏览器兼容如何折腾人,做前端开发的总能迎刃而解的!

Jquery中对新增对象live绑定时间hover的另类处理

Jquery中对新增对象live绑定时间hover的另类处理:

在项目中发现对新增对象使用hover方法时,live的绑定方式貌似不大对,结果测试页的确说明绑定的hover时间无效,翻阅jquery API发现live只能绑定这类事件:

在jQuery 1.4.1 中,.live() 能接受多个,用空间分隔事件,在提供类似.bind()的功能 。例如,我们可以“live ” 同时绑定mouseovermouseout事件,像这样:

$('.hoverme').live('mouseover mouseout', function(event) {
if (event.type == 'mouseover') {
// do something on mouseover
} else {
// do something on mouseout
}
});

随后又发现:

$(".hoverme").live({ 
  mouseenter: function() { //todo }, 
  mouseleave: function() { //todo }
});

这个比较能够接近hover实现的效果,至于实际应该怎么用看实际应用情况而定。

解决IE7中异步加载使用jquery的append方法导致Select无法自适应宽度的问题

解决IE7中异步加载使用jquery的append方法导致Select无法自适应宽度的问题

在项目中省市区三级联动用到了ajax请求数据,在页面处理方面使用Jquery框架的$().append(‘<option>xxx</option>’)方法写入Select控件。经测试在IE7中Select加载数据后宽度位置竟然无变化且重叠在一起。

尝试使用js原生方法的options.add可以解决此问题,几经纠结最终还是喜欢用jquery的方法:$(“Select”).hide().show();对Select对象进行hide show操作后可以恢复占位。

js中最简单实现replaceALL的方法

今天在实际项目中需要用到替换原字符串内所有的含有指定字符串的javascript方法,经过一番思考和查阅资料,可以通过js的正则进行全局替换,最简便方法如下:

String.prototype.replaceAll = function(s1,s2) { 
    return this.replace(new RegExp(s1,"gm"),s2); 
}

PS:博主最开始也走过弯路,通过循环替换的方式遍历字符串中所有的指定字符串进行替换,但显然这是一种伤人伤己的方案(一想到出现N个遍历替换,浏览器直接死掉)。

return top