1.正则表达式检测是否为URL——总结正则表达式相关知识
正则表达式测试工具 http://tool.chinaz.com/regex/ 通过这个可以检测我们的正则表达式是否匹配了希望的内容。
下面用十点简要总结正则表达式的一些基本用法。
一,创建一个正则表达式
var reg = /pattern/; 或 var reg = new RegExp('pattern');
二,正则表达式方法
reg.exec(str); 或 str.match(reg); 都是返回数组,exec只返回第一个匹配即只有一个元素的正则信息数组while(match=reg.exec(str))console.log(match[1])遍历输出匹配到的字符串,而match是在指定全局g时返回每一个匹配。
reg.test(str); 返回布尔值以表示是否成功
str.replace(reg,'c'); 将str字符串中匹配reg的部分用’’代替,结果作为返回值被返回
str.search(reg); 返回正则表达式第一次匹配的位置
str.split(reg); 返回分割后的数组
三,限制匹配个数的语法规则
1. c{n} { 1}表示一个的意思。/c{1}/只能匹配一个c。 /c{n}/则会匹配n个连续的c。reg = /c{1}/;str='cainiao';execReg(reg,str);返回结果creg = /c{2}/;str='cainiao';execReg(reg,str);返回结果null,表示没有匹配成功。2. c{m,n}c{ 3,4}的意思是,连续的3个c或者4个c。reg = /c{3,4}/;str='ccccTest';execReg(reg,str);结果返回cccc,这表明正则会尽量多品牌,可3可4的时候它会选择多匹配一个。3. c{n,}c{ 1,}表示1个以上的c。例如:reg = /c{1,}/;str='cccccTest';execReg(reg,str);返回ccccc,再次说明了正则表达式会尽量多地匹配。reg = /c{2,}/;str='cainiao';execReg(reg,str);结果返回null,c{ 2,}表示2个以上的c,而cainiao中只有1个c。4. * + ? 与转意\* \+ \?* 表示0次或者多次,可有可无,等同于{0,},即c* 和 c{0,} 是一个意思。+ 表示一次或者多次,必须出现,等同于{1,},即c+ 和 c{1,} 是一个意思。? 表示0次或者1次,可无可有一次,等同于{0,1},即c? 和 c{0,1} 是一个意思。如果我们真的想匹配’c*’这个字符串的时候,就要将*转义reg = /c\*/;str='c*';execReg(reg,str);返回匹配的字符串:c*。同理,要匹配其他元字符,只要在前面加上一个“\”就可以了。5. 贪心模式与非贪心模式只要在合法的情况下,正则会尽量多去匹配字符,叫做贪心模式。如果我们希望正则尽量少地匹配字符,那么就可以在表示数字的符号后面加上一个?变成非贪心模式。{n,}?, *?, +?, ??, {m,n}?reg = /c{1,}?/;str='ccccc';execReg(reg,str);返回的结果只有1个c,尽管有5个c可以匹配,但是由于正则表达式是非贪心模式,所以只会匹配一个。
四,边界\b 非边界\B /^开头 $/结尾匹配
\b表示的边界的意思,也就是说,只有字符串的开头和结尾才算数。例如/\bc/就表示字符串开始的c或者是结尾的c。看下面的例子:reg = /\bc/;str='cainiao';execReg(reg,str);返回结果c。匹配到了左边界的c字符。reg = /\bc/;str='维生素c';execReg(reg,str);仍然返回c,不过这次返回的是右侧边界的c。reg = /\bc/;str='bcb';execReg(reg,str);这次匹配失败,因为bcb字符串中的c被夹在中间,既不在左边界也不再右边界。与\b对应\B表示非边界。例如:reg = /\Bc/;str='bcb';execReg(reg,str);这次会成功地匹配到bcb中的c,而reg = /\Bc/;str='cainiao';execReg(reg,str);则会返回null。因为\B告诉正则,只匹配非边界的c。
^表示只匹配字符串的开头。看下面的例子: reg = /^c/; str='维生素c'; execReg(reg,str); 结果为null,因为字符串‘维生素c’的开头并不是c,所以匹配失败。 reg = /^c/; str='cainiao'; execReg(reg,str); 这次则返回c,匹配成功,因为cainiao恰恰是以c开头的。 与^相反,$则只匹配字符串结尾的字符: reg = /c$/; str='维生素c'; execReg(reg,str); 这次返回的结果是c,表明匹配成功。
五,代表任意非\n的点’.’
reg = /./;str='cao';execReg(reg,str);结果显示,正则匹配到了字符c。reg = /.+/;str='blue——经典 好_。';execReg(reg,str);结果是所有的字符都被匹配掉了,包括一个空格,一个下滑线,和一个破折号。reg = /^./;str='\ncaao';execReg(reg,str);结果是null,终于失败了,正则要求字符串的第一个字符不是换行,但是恰恰字符是以\n开始的。
六,正则表达式中的或,“|“
b|c表示,匹配b或者c。reg = /b|c/;str='blue';execReg(reg,str);结果是b。reg = /^b|c.+/;str='caao';execReg(reg,str);匹配开头的b或者是c.+,c开头则匹配掉整个caao。
七,子正则表达式的括号与其多义
reg = /^(b|c).+/;str='bbs.blueidea.com';execReg(reg,str);这次的结果是整个串bbs.blueidea.com,加上上面的括号这后,正则表示,如果字符串的开头是b或者c,那么匹配开头的b或者c以及其后的所有的非换行字符。
捕获
| (exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?’name’exp) | |
(?:exp) | 匹配exp,不捕获匹配文本,也不给分组分配组号 | |
断言
| (?=exp) | 匹配exp前面位置,但是不匹配exp |
(?<exp) | 匹配exp后面位置,但是不匹配exp | |
(?!exp) | 匹配后面的不是exp的位置,但是不匹配exp | |
(?<!exp) | 匹配前面不是exp的位置,但是不匹配exp |
小括号的多义,分组捕获。
var reg1 = /(\d{3}) (\d{3})/var str = '111 222'str.replace(reg1, '$2 $1') // => '222 111' , 注意这里的$2,$1,存放了匹配的字符串 var reg2 = /(\d{3})(\d{4})(\d{4})/var mobile = '13522722724'reg2.test(mobile)RegExp.$1 // => 135RegExp.$2 // => 2272RegExp.$3 // => 2724 var reg3 = /(\d{3})(\d{4})(\d{4})/var mobile = '13522722724'mobile.replace(reg3, '$1 $2 $3') // => '135 2272 2724'
较长的正则表达式中,反向引用会降低匹配速度,性能降低,不需要反向引用时应使用分组不捕获,括号前加?:。
另外正则有一个限制相邻信息而不实际匹配的语法,括号前加?=。最适合的例子就是将12个数字分拆成3组4个数字,.replace(/(\d{4})(?=\d)/g,
"$1 "
)
。
在/g全局匹配基础上,逐4个替换成$1+空格,当第三组不满足后面为数字的相邻限制,不做替换,最后没有冗余空格。
var reg = /(John) (?=Resig)/reg.test('John') // => falsereg.test('John Backus') // => falsereg.test('John Reisg') // => trueRegExp.$1 // => 'John',注意这里不是 "John Resig"
参考: http://www.cnblogs.com/dwlsxj/p/Regex.html
另外,正则表达式\+数字n表示匹配的第n个group
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:
1 ((A)(B(C))) 2 \A 3 (B(C)) 4 (C) 组零始终代表整个表达式。 之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器检索。 /^(11+?)\1+$/ 解释:以11开头的非贪婪模式匹配至少2个连续的1,作为组1被匹配1次或多次(被用来检测1的个数是否为素数)。(\w)((?=\1\1\1)(\1))+ 解释:重复4次或以上的字母匹配除最后两位之前的部分
Java中Matcher.group(n) 和 s.substring(m.start(n), m.end(n)) 是等效的
八,一个字符[abc] 反[^abc]
[abc]表示a或者b或者c中的任意一个字符,[^abc]就表示不能是a,b或者c中的任何一个。^在正则表达式开始部分的时候表示开头的意思,例如/^c/表示开头是c;但是在字符集和中,它表示的是类似“非“的意思。reg = /^[abc]/;str='bbs';execReg(reg,str);返回结果是b。reg = /[^abc]/;str='blue';execReg(reg,str);返回的结果是l,因为它是第一个非abc的字符(即第一个b没有匹配)。在字字符集合中可以使用如下的表示方式:[a-z],[A-Z],[0-9],分别表示小写字母,大写字母,数字。例如:reg = /^[a-zA-Z][a-zA-Z0-9_]+/;str='test';execReg(reg,str);结果是整个test,正则的意思是开头必须是英文字母,后面可以是英文字母或者数字以及下划线。
九,数字\d 非数字\D 英文字符\w
\d表示数字的意思,相反,\D表示非数字。例如:reg = /\d/;str='cao8';execReg(reg,str);返回的匹配结果为8,因为它是第一个数字字符。reg = /\D/;str='cao8';execReg(reg,str);返回c,第一个非数字字符。\w表示英文字符,等同于字符集合[a-zA-Z0-9_]。例如:reg = /\w+/;str='blue';execReg(reg,str);返回完整的blue字符串,因为所有字符都是单词字符。reg = /\w+/;str='.className';execReg(reg,str);结果显示匹配了字符串中的className。\W表示非单词字符,等效于[^a-zA-Z0-9_]reg = /\W+/;str='中文如何?';execReg(reg,str);返回完整的字符串,因为,无论是中文和“?”都算作是非单词字符。
十,几种空白字符匹配
\f匹配换页符,\n匹配换行符,\r匹配回车,\t匹配制表符,\v匹配垂直制表符。\s匹配单个空格,等同于[\f\n\r\t\v]。例如:reg = /\s.+/;str='This is a test String.';execReg(reg,str);返回“is a test String.”,正则的意思是匹配第一个空格以及其后的所有非换行字符。同样,\S表示非空格字符。reg = /\S+/;str='This is a test String.';execReg(reg,str);匹配结果为This,当遇到第一个空格之后,正则就停止匹配了。
实例
用正则表达式写Encode与Decode
/*1.用浏览器内部转换器实现html转码*/ htmlEncode:function (html){ //1.首先动态创建一个容器标签元素,如DIV var temp = document.createElement ("div"); //2.然后将要转换的字符串设置为这个元素的innerText(ie支持)或者textContent(火狐,google支持) (temp.textContent != undefined ) ? (temp.textContent = html) : (temp.innerText = html); //3.最后返回这个元素的innerHTML,即得到经过HTML编码转换的字符串了 var output = temp.innerHTML; temp = null; return output; }, /*2.用浏览器内部转换器实现html解码*/ htmlDecode:function (text){ //1.首先动态创建一个容器标签元素,如DIV var temp = document.createElement("div"); //2.然后将要转换的字符串设置为这个元素的innerHTML(ie,火狐,google都支持) temp.innerHTML = text; //3.最后返回这个元素的innerText(ie支持)或者textContent(火狐,google支持),即得到经过HTML解码的字符串了。 var output = temp.innerText || temp.textContent; temp = null; return output; }, /*3.用正则表达式实现html转码*/ htmlEncodeByRegExp:function (str){ var s = ""; if(str.length == 0) return ""; s = str.replace(/&/g,"&"); s = s.replace(//g,">"); s = s.replace(/ /g," "); s = s.replace(/\'/g,"'"); s = s.replace(/\"/g,"""); return s; }, /*4.用正则表达式实现html解码*/ htmlDecodeByRegExp:function (str){ var s = ""; if(str.length == 0) return ""; s = str.replace(/&/g,"&"); s = s.replace(/</g,"<"); s = s.replace(/>/g,">"); s = s.replace(/ /g," "); s = s.replace(/'/g,"\'"); s = s.replace(/"/g,"\""); return s; }
综合写出检测一个字符串是否为一个有效URL的JS正则表达式程序
http://www.iteye.com/topic/481228
检查邮箱地址格式
n = n.replace(/[。|,|,|、]/g, "."), /^[A-Z_a-z0-9-\.]+@([A-Z_a-z0-9-]+\.)+[a-z0-9A-Z]{2,4}$/.test(n)
IP合法性检测 使用正则分组,四部分都不能大于255
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
2.遍历与事件响应,计时器
1:首先页面加载时马上响应JS代码如下运行(不一定要等所有的JS和图片加载完毕,就可以执行方法):
$(document).ready(function(){});
另一种简单写法:
$(function () {})
2:当然有些必须要等到所有元素都加载完才可以执行JS方法,可以如下面这种写法:
$(window).load(function() { });
3:还有一种是DOM元素加载之前执行Jquery代码:
(function() { })(jQuery)
对body中多个按钮定义onclick事件,用window.event.srcElement得到操作的按钮。
HTML
clearInterval(inervalId);
时钟实现
Untitled Document
屏幕数值获取与html注入,模拟QQ虚假弹窗
Untitled Document
运用计时器制作淡入淡出的侧边分享栏
Untitled Document 分享到
3.运动框架
已经封装好的JS运动框架代码,传入Object和JSon,就可以对对象进行style数值运动变化。
注意要将计时器设置在对象上,opacity属性特殊处理。
在Jquery中有.animation({json},'slow',func(){}) 就可以作为我们的运动框架了。
一些特殊效果也有如 fadeIn(500)/fadeOut(500)/fadeTo(0.5, 500) slideUp(500) 灵活使用
function getstyle(obj,name){ if(obj.currentStyle){ return obj.currentStyle[name]; }else{ return getComputedStyle(obj,false)[name]; }} function startMove(obj,json,func){ clearInterval(obj.timer); obj.timer=setInterval(function(){ var check=true; for(var attr in json){ var cur=0; if(attr=='opacity'){ cur=parseInt(parseFloat(getstyle(obj,attr))*100); } else { cur=parseInt(getstyle(obj,attr)); } var speed=(json[attr]-cur)/6; speed=speed>0?Math.ceil(speed):Math.floor(speed); if(cur!=json[attr]){ check=false; if(attr=='opacity'){ obj.style.filter='alpha(opacity:'+(cur+speed)+')'; obj.style.opacity=(cur+speed)/100; } else obj.style[attr]=cur+speed+'px'; } } if(check){ clearInterval(obj.timer); if(func) func(); } },30);}
在HTML中调用运动框架JS文件
Untitled Document
4.DOM操作
HTML代码对应一颗DOM树。对DOM的各种操作事实上都是对这颗DOM树展开的。
1. 查找节点
主要是通过jQuery选择器来完成。结合文章开头的DOM树实例就行说明。
1 var $li=$("ul li:eq(0)"); //查找ul中第一个
2. 创建节点
创建元素节点并不只是单单创建元素节点,还需要将其挂到DOM树上。例如我们创建一个<li>节点然后将其挂在<ul>上,具体代码如下:
var $li_new=$(""); //创建一个
- 下
3. 插入节点
一种插入节点的方法是通过jQuery中的append()方法,下面通过表1将插入节点的各种方法进行总结。
表1 插入节点的各种方法
方法 | 描述 | 示例 |
append() | 向每个匹配元素内部追加节点或是内容 | HTML代码:<p>你好吗?</p> jQuery代码:$("p").append(“<b>还不错哦.</b>”); 结果:<p>你好吗?<b>还不错哦.</b></p> |
appendTo() | $(A).append(B):是将B追加到A上 $(A).appendTo(B):是将A追加到B上 | HTML代码:<p>你好吗?</p> jQuery代码:$("<b>还不错哦.</b>").appendTo(“p”); 结果:<p>你好吗?<b>还不错哦.</b></p> |
prepend() | 向每个匹配的元素内部追加内容 | HTML代码:<p>你好吗?</p> jQuery代码:$("p").prepend(“<b>还不错哦.</b>”); 结果:<p><b>还不错哦.</b>你好吗?</p> |
prependTo() | $(A).prepend(B):是将B追加到A上 $(A).prependTo(B):是将A追加到B上 | HTML代码:<p>你好吗?</p> jQuery代码:$("<b>还不错哦.</b>").aprependTo(“p”); 结果:<p><b>还不错哦.</b>你好吗?</p> |
after() | 在每个匹配的元素之后添加内容 | HTML代码:<p>你好吗?</p> jQuery代码:$("p").after(“<b>还不错哦.</b>”); 结果:<p>你好吗?</p><b>还不错哦.</b> |
insertAfter | $(A).after(B):将B插入到A后 $(A).insertAfter(B):将A插入到B后 | HTML代码:<p>你好吗?</p> jQuery代码:$(“<b>还不错哦.</b>”).insertAfter(“p”); 结果:<p>你好吗?</p><b>还不错哦.</b> |
before() | 在每个匹配元素之前插入内容 | HTML代码:<p>你好吗?</p> jQuery代码:$(“p”).before(“<b>还不错哦.</b>”); 结果:<b>还不错哦.</b><p>你好吗?</p> |
insertBefore() | $(A).before(B):将B插入到A前 $(A).insertBefore(B):A插入到B前 | HTML代码:<p>你好吗?</p> jQuery代码:$(“<b>还不错哦.</b>”).insertBefore(“p”); 结果:<b>还不错哦.</b><p>你好吗?</p> |
4. 删除节点
jQuery中提供了三种方法删除多余的节点。
remove()方法
$("ul li:eq(0)").remove(); //获取ul下的第一个
值得注意的有两点:1.经remove()方法删除后的节点还可以恢复, 例如上述代码被删除后可以通过以下代码恢复
1 var $li_delete=$("ul li:eq(0)"); //获得ul下第一个li节点2 $li_delete.remove(); //将该节点删除3 $("ul").append($li_delete); //在将被删除的节点添加到ul上,需要注意的是此时该li节点被放置到ul的最后面
remove()参数,指定某属性的标签删除
1 $("ul li").remove(“li[title=篮球]”); //在
- 下,删除属性title为篮球的li的节点
detach()方法
具体用法与remove方法基本一样。与remove()方法相同的是该方法在删除元素节点后,也可以恢复元素。与remove()方法不同的是该方法删除所匹配的元素时,并不会删除该元素所绑定的事件、附加的数据,比如说:一个<p>绑定了一个click(function(){ alert("能恢复吗?");});事件,如果用remove()删除之后,再次恢复该元素时候并不会恢复click()事件,而detach()方法则在恢复时,同时也可以恢复其click()事件。
empty()方法
准确的说,empty()方法并不是删除节点,而是清空节点,清空元素中的所有后代节点。最后只剩一个空节点(该元素的属性依然存在)。例如我们清空第三个羽毛球的<li>节点。可以用下述代码完成。
1 $("ul li:eq(2)").empty; //清空该节点
5. 复制节点
通过使用clone()方法,如果只写clone()则表示说明只复制节点,复制节点后,被复制的新元素并不具有任何行为。
如果想复制原节点所绑定的行为(事件),那么写法应该为clone(true).
6.替换节点与包裹节点
两个方法replaceWith()与replaceAll(): $(A).replaceWith(B):用B替换A
$(A).replaceAll(B):用A替换B
$("p").wrap(""""); 用标签将包裹起来
7. 属性操作
1. 获取属性和设置属性
通过使用attr()获取属性的值,参数可以为多个。执行下述代码就会弹出“你最喜欢的运动”.
var $p=$("p"); //获取节点var p_text=$p.attr("title"); //获取节点
的属性title的值
2. 删除属性
通过removeAttr();如下例代码。
1 $("p").removeAttr("title"); //删除的title属性
8. 样式操作
1.获取样式和设置样式
我们知道,在HTML中改变样式的方法是通过CSS来完成的,一般都通过在元素中定义id或者class,而id或者class也输入该元素的一个属性,故可以通过attr()方法来获取和设置其属性。例如<p>标签中原始属性是class=start,在CSS中又定义了一个end的样式。这时我们就可以通过以下代码进行设置样式。
1 $("p").attr("class",“end”); //将标签的样式class从start该为end
2. 追加样式
通过jQuery中提供的addClass()方法进行追加样式,值得注意的是addClass()是该原先的样式中添加了一种新的样式(多了一种样式,如果以前样式是一种则使用该方法后样式变为两种),而attr()则是该变了元素的初始样式(样式没有增多)。
3. 移除样式
通过jQuery中的removeClass()方法。如果参数为空,则代表是移除其所有的样式。
4. 切换样式
通过使用jQuery中的toggle()方法,该方法在jQuery中有着广泛的应用,以后要出一篇blog要把常用的jQuery方法进行总结。这里只说toggle()方法应该如何切换样式。实际上,通过的是tooggleClass()方法进行切换。该方法可以控制样式的重复切换,如果类名存在就删除它,如果类名不存在就添加它。示例代码如下。
1 $("p").tooggleClass("another"); //重复切换类名anohter
5. 判断是否含有某个样式
通过hasClass()方法进行判断,如果有则返回true,没有返回false。
6. 设置样式
.css控制sytle对象的各种样式属性。
1 $("p").css({"color":"red","font-size":"14px"}); //设置的颜色和字体
9. 设置和获取HTML、文本、值
1. html()方法
该方法类似于javascript中的innerHTML属性,获取的是HTML代码。
2.text()方法
该方法类似于javascript中的innerText属性,获取的是文本内容。
3.val()方法
该方法类似与javascript中的value属性,获取或者设置元素的值。需要注意的是,如果获取的是多个元素,那么返回值也将是含多个元素值的集合。
10. 遍历节点
1.children()方法:节点的子元素,而不考虑后代元素,即DOM树一个节点的直接子节点。
2.next()方法:获得匹配元素后面紧邻的同辈元素。
3.prev()方法:获得匹配元素前面紧邻的同辈元素。
4.siblings()方法:取得匹配元素前后所有的同辈元素。
运用DOM和运动框架制作模仿微博的发布效果。
Untitled Document 大家都在说
5.JS的面向对象
通过new构造函数创建一个对象,并给对象定义方法。
通过call继承父对象,通过引用或复制来继承方法。
call和apply,作用都是将函数绑定到另外一个对象上去运行
格式和参数定义:
A.call( B [,arg1,arg2,… ] ); // 参数列表,arg1,arg2,...
将A作为对象B的一个方法运行
辨析:http://blog.csdn.net/ithomer/article/details/6592082 .
下面是一个实例,用来懒加载图片,其中将callback作为对象img的方法运行。
function loadImage(url,callback) { var img = new Image(); img.src = url; if(img.complete) { // 属性判断图片是否已经存在于浏览器缓存 callback.call(img); return; // 直接返回,不用再处理onload事件 } img.onload = function(){ img.onload = null; callback.call(img); }}
实例2:
style要设置成绝对位置,style位置属性要为字符串px的,可通过offsetLeft等属性获得数值。
注意window.event.clientX只有在鼠标事件中才有效,下面是实现对div拖拽的程序。
本程序将程序封装成对象Drag,注意其中对this属性的分辨和记录。
Untitled Document aaabbb
用面向对象的方法写成的电话号码格式化验证功能的JS
$(function() { new numConfirm().addEvent();})function numConfirm() { this.splitType = [3, 4, 4];}numConfirm.prototype = { _position : function(target) { var self = this; var elemWidth = $(target).outerWidth(), elemHeight = $(target).outerHeight(), elemParent = $(target).parents('.parentCls'), containerHeight = $('.js-max-input', elemParent).outerHeight(); $(elemParent).css({ "position" : 'relative' }); $('.js-max-input', elemParent).css({ 'position' : 'absolute', 'top' : -elemHeight - containerHeight / 2, 'left' : 0 }); }, addEvent : function() { var self = this; $('.inputElem').each(function(index, item) { $(this).keyup(function(e) { var value = $.trim(e.target.value); if (value == '') { $('.js-max-input').hide(); } else { $('.js-max-input').show(); } var count = 0, output = []; for (var i = 0; i < self.splitType.length; i++) { var s = value.substr(count, self.splitType[i]); if (s.length) { output.push(s); } count += self.splitType[i]; } value = output.join('-'); $('.js-max-input').text(value); self._position($(this)); }); }); }};
6、事件冒泡与阻止冒泡
当事件发生后,这个事件就要开始传播,因为事件源本身并没有处理事件的能力需要委托DOM树父节点。例如我们点击一个按钮时,就会产生一个click事件,但这个按钮本身不能处理这个事件,事件必须从这个按钮传播出去,从而到达能够处理这个事件的代码中(例如我们给按钮的onclick属性赋一个函数的名字,就是让这个函数去处理该按钮的click事件)。
当事件在传播过程中,找到了一个能够处理它的函数,这时候我们就说这个函数捕捉到了这个事件。 说到这里,关键的问题来了,那就是一个函数是如何捕捉一个事件的呢?这就涉及到事件的冒泡了。 为了更好地理解冒泡的概念,现在想象一下你的面前放着一杯水,但这杯水和我们平时看到的有点点不同,它分为数层,每一层又分成一或多个区域,最顶层是我们熟悉的窗口对象(即window对象),下一层分为好几个区域(document对象、history对象等等),而document对象的下一层又分为多个子对象。 这些对象的层次关系构成了DOM中的对象树。 事件的传播是有方向的,当点击一个按钮时所产生的事件从这个按钮处开始向上传播(就像一个水泡从杯底冒上来,这就是之所以叫事件冒泡的原因),但这个事件总是寻找特定的属性是否有值。例如按钮的click事件先寻找在按钮上是否有onclick属性的有意义的定义(即该属性指向一个存在的函数或一段可执行的语句),如果有,执行这个函数或语句;然后事件继续向上传播,到达按钮的上一层对象(例如一个form对象或document对象,总之是包含了按钮的父对象),如果该对象也定义了onclick属性,则执行属性的值。 所以,如果这个按钮上面有3层(form、document、window),且这三层都定义了onclick属性,则当按钮的click事件产生时,将会调用4个(包括按钮本身的一个)函数或执行4段语句。在火狐Firefox、opera、IE下阻止冒泡事件是不同的代码的,火狐下使用的是event.stopPropagation(),而IE下使用的是cancelBubble,jQuery 可以使用e.stopPropagation()就可以兼容了。
img.onmouseup = function(e){ e = e || window.event; if(e.stopPropagation){ e.stopPropagation(); }else{ e.cancelBubble = true; } }
附百度划词搜索的JS代码
var baidusearch = (function(){ function init(tn){ addEV(document, 'mouseup', fn); function fn(){ var isStandard = "getSelection" in window; var ico_img = document.getElementById('selectsearch-icon'); if(ico_img){ ico_img.parentNode.removeChild(ico_img); } setTimeout(function(){ selection = isStandard ? window.getSelection() : document.selection.createRange() var text = (isStandard ? selection+'' : selection.text).replace(/\n+/g, ''); if(text && text.length){ if(text.length > 76){ text = text.substring(0, 76); } show(isStandard, selection, text); } }, 25); } function show(isStandard, selection, text){ var scrollTop = document.body.scrollTop + document.documentElement.scrollTop; var scrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft; if(isStandard){ var rangePos = selection.getRangeAt(0).getBoundingClientRect(); if(rangePos.top==0 && rangePos.right==0) return; var tempTop = rangePos.top>35 ? rangePos.top-35+scrollTop : scrollTop; var tempLeft = rangePos.right+70>document.documentElement.clientWidth ? document.documentElement.clientWidth-65+scrollLeft : rangePos.right+5+scrollLeft; }else{ var selectionLeft = selection.boundingLeft+selection.boundingWidth; var tempTop = selection.boundingTop>35 ? selection.boundingTop-35+scrollTop : scrollTop; var tempLeft = selectionLeft+70>document.documentElement.clientWidth ? document.documentElement.clientWidth-65+scrollLeft : selectionLeft+scrollLeft; } var text = encodeURI(text); var img = document.createElement('img'); img.src = 'http://img.baidu.com/img/iknow/qb/select-search.png'; img.alt = '搜索'; img.style.cssText = "width:65px; height:31px; border:0px none;"; var link = document.createElement('a'); link.id = 'selectsearch-icon'; link.style.cssText = "cursor:pointer; position:absolute;" link.href = 'http://www.baidu.com/s?wd='+text+'&tn='+tn+'&hl_tag=flayer'; link.target = '_blank'; link.onclick = function(){ link.parentNode.removeChild(link); } link.style.left = tempLeft + 'px'; link.style.top = tempTop + 'px'; link.appendChild(img); document.body.appendChild(link); img.onmouseup = function(e){ e = e || window.event; if(e.stopPropagation){ e.stopPropagation(); }else{ e.cancelBubble = true; } } } function addEV(d,b,a){ if(window.attachEvent){d.attachEvent("on"+b,a)}else{ if(window.addEventListener){d.addEventListener(b,a,false)}}} }; return { 'init' : init }})();