标签:
在我之前写的DOM基础(一)的文章中提到过兼容性的问题,也就是在获取标签间文本信息的时候,早期的火狐版本是不支持innerText的,只支持textContent ,现在的火狐浏览器两者都支持。而IE老版本,也是IE8之前的版本,包括IE8是不支持textContent的,只支持innerText。那要如何解决这个问题呢,我们总不能规定用户兼容我们写的代码的浏览器吧。毕竟顾客是上帝这句话是不变的真理,同样的,对于互联网来说,用户就是上帝。其实做为一个前端开发者来说,痛恨的不是顾客为什么不用好的浏览器,而是IE为什么要这么任性,总是有着无数的兼容性问题。可是没办法,毕竟人家兼容性再差,它还是有这么高的市场份额。所以,做为最悲催的开发者,只能默默的承受着这份广为人知的辛酸。好了,题外话就不多说了,现在进入正题。
既然获取标签中文本存在着兼容性问题,那么我们只能写它的兼容性代码,使得它能满足各个主流版本的浏览器。一般情况下,我们把兼容性代码封装在一个函数中。比如当前要封装的获取标签中文本的代码。
function getInnerText(obj){ if(obj.innerText){ //IE8及之前的早期浏览器版本支持的 return obj.innerText; }else { return obj.textContent; // 火狐早期版本支持的 } }
现在我们来分析下这段代码,他是用来做获取标签之间文本的兼容性的。首先就是函数的名字,给函数取名也并不是那么简单的,在js中的命名规范基本上都遵守驼峰命名法,也就是第一个单词小写,之后跟的每一个有意义的单词首字母大写。除了构造函数,它一般是一个首字母大写的单词。另外,取得名字最好直观易懂,尽量不用没有意义的单词,比如var num=123;就比var a=123;来的更直观易懂。不过,这些只是JS中的规范,并不是必须的,只不过,这些规范都是强烈推荐的,因为规范能使代码的可读性更高,在工作中或者看自己以前写的代码的时候也能带来更多的便利。
好了,命名好函数之后,我们给他传入了一个参数。在这里,这个参数是用来传入要操作的标签的,也就是要获取文本内容的标签。函数里则是一个if-else结构的语句,在这个函数中,是用来做能力检测的,也就是做兼容的。if后小括号内跟的是obj.innerText,这个判断是整段代码的核心,在调用这个函数的时候,我们传入了一个要操作的对象,然后进入到函数中,首先就是进行判断,如果浏览器有obj.innerText这个方法,obj.innerText这个值就是存在的,也就是true,这时候直接返回obj.innerText就好了。如果浏览器没有obj.innerText这个方法,那么obj.innerText的值是undetfined,就是false,然后就执行else中的代码。返回一个obj.textContent。这样,一段兼容老版本火狐跟ie8之前的浏览器的兼容性代码就写好了。
其实,所谓的兼容性,就是看浏览器是否支持当前对象的属性或是方法,如果支持就说明是兼容,如果不支持,就说明不兼容。
之前,我提到过DOM中的鼠标单击事件,其实在DOM中,还有很多其他的常用事件,下面我列举了一些平时用的比较多的事件。
事件名 |
说明 |
onclick |
鼠标单击 |
ondblclick |
鼠标双击 |
onkeyup |
按下并释放键盘中的一个键时触发 |
onchange |
文本内容或下拉菜单中的选项发生改变 |
onfocus |
获得焦点,表示文本框等获得鼠标光标 |
onblur |
失去焦点,表示文本框等失去鼠标光标 |
onmouseover |
鼠标悬停,即鼠标等停留在图片等的上方 |
onmouseout |
鼠标移出,即离开图片等所在的区域 |
onload |
网页文档加载事件 |
onunload |
关闭网页时 |
onsubmit |
表单提交事件 |
这里列举的事件都比较简单,只是提了下这些事件所能实现的功能,没有提到他们的具体属性和试用哪些标签。不过他们的用法跟前一篇文章中的鼠标单击用法是基本一样的。在使用这些事件的时候,可以先查一下W3C手册来看他们具体的使用方法。也可以查https://developer.mozilla.org/zh-CN/这个网址,这是个我目前也在用的一个挺不错的网站,而且写得内容也很全。下面我就举几个典型的例子来看看上面这些事件的使用方法。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="text" value="请输入内容"/> <script> var input = document.getElementsByTagName("input")[0]; input.onfocus = function () { if (input.value == "请输入内容") { input.value = ""; } } input.onblur = function () { if (input.value == "") { input.value = "请输入内容"; } } </script> </body> </html>
上面这段代码写了一个输入框。当进入进入时,提示文字消失,当鼠标离开时,输入框内如果没有内容的话则显示提示文字。这其实就是输入框获得焦点和失去焦点的两个事件,当鼠标移入时输入框获得焦点,执行匿名函数,判断输入框中的值是否为提示信息,如果是,则变为空。而当鼠标点击输入框之外的内容时,输入框失去焦点,这时候执行匿名函数判断输入的内容是否为空,如果为空,则显示提示信息。从这个例子看,事件也并不是很难。接下来就是一个排他思想的鼠标单击事件。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> .Box{ width: 240px; border: 1px solid #000; margin:100px auto; padding:20px; } .con{ width: 100%; height: 200px; border: 1px solid #000; margin-top:10px; display:none; } .current{ background-color: pink; } </style> </head> <body> <div class="Box" id="box"> <button class="current" >按钮1</button> <button >按钮2</button> <button>按钮3</button> <button>按钮4</button> <div class="con" style="display:block">内容1</div> <div class="con">内容2</div> <div class="con">内容3</div> <div class="con">内容4</div> </div> <script> var btns = document.getElementsByTagName("button"); var box = document.getElementById("box"); var divs = box.getElementsByTagName("div"); for(var i=0;i<btns.length;i++){ btns[i].aa=i; btns[i].onclick = function(){ for(var j=0;j<btns.length;j++){ btns[j].className = ""; divs[j].style.display = "none"; } this.className = "current"; divs[this.aa].style.display = "block"; } } </script> </body> </html>
执行上述代码,我们可以看到页面上有四个按钮和一个内容显示区域当我们点击其中一个按钮时,这个按钮变成粉红色,而其他的不变。内容区则变成对应按钮所要显示的内容区域。当我们点击另一个按钮时,那个按钮变为粉红色,内容区域也跟着改变,而另外的按钮则都是原来的颜色。要实现这段代码,又两个重点,首先就要获取页面中所有的按钮,然后给每个按钮都绑定一个鼠标单击事件,在单击当前按钮时,先循环遍历一次所有的按钮,让他们的类样式都变为空。而在按钮点击和样式改变的同时,下面的内容也要改变,所以,在鼠标单击时,我们除了要循环遍历所有按钮给他们的类样式设置为空的同时,也要循环遍历所有的内容div,给他们的样式设置为隐藏。循环完之后,再给当前鼠标点击的按钮设置类样式,使他的颜色改变,而div内容区域跟按钮一一对应,所以我们点击第几个按钮,就让第几个div的样式变为显示,这时候,我们就要获取点击的按钮的下标。不过,就上述代码为例,我们并不能直接用j来获取,因为在解析的时候,所有的循环已经执行完成了,而匿名函数内的代码则是事件触发时才会执行,所以,如果我们用j,那么这个j的值恒等于4,因而程序就不能像我们想要的那样执行了,那要怎么获得这个下标呢?我们可以再函数外定自定义一个属性来保存按钮的下标(自定义属性我会在本文后面有详细的解释)。在函数里,用this的方法获取下标,这样,点击按钮让对应的内容区域显示这个功能就完成了。
接下来这个是鼠标移入跟移出事件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> .nodeSmall1{ width: 50px; height: 50px; background: url(images/bgs.png) no-repeat -159px -51px; position: fixed; right: 10px; top: 40%; } .erweima { position: absolute; top: 0; left: -150px; } .nodeSmall1 a { display: block; width: 50px; height: 50px; } .hide { display: none; } .show { display: block; } </style> </head> <body> <div class="nodeSmall1" id="node_small1"> <a href="#"></a> <div class="erweima hide" id="er1"> <img src="images/456.png" alt=""> </div> </div> <script src="common.js"></script> <script> var nodeSmall = $$("node_small1"); var er = $$("er1"); // nodeSmall.onmouseover = function(){ // er.className = "erweima show"; // } // nodeSmall.onmouseout = function(){ // er.className = "erweima hide"; // } nodeSmall.onmouseover = function(){ // 鼠标移入 er.className = er.className.replace("hide","show"); } nodeSmall.onmouseout = function(){ // 鼠标离开 er.className = er.className.replace("show","hide"); } </script> </body> </html>
上述代码中,在页面右侧定义了一个二维码的图标,(这里的图片我就不上传了,在使用这段代码的时候用其他任意的图片代替就好了)当鼠标移入这个图标的时候,触发onmouseover事件,给大的二维码设置属性来让他显示,这里我提供了两种显示方式,一种是直接改他的属性名,(也就是我注释的哪一种),另一种则是使用了替换的方式来改变属性名中要改变的值。下面这个案例则是一个点餐案例
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> * { margin: 0; padding: 0; } .wrap { width: 300px; margin: 100px auto; } table { border-collapse: collapse; /*倒塌,合并边框*/ border-spacing: 0; /*边框间隔*/ border: 1px solid #c0c0c0; width: 300px; } th, td { border: 1px solid #d0d0d0; padding: 10px; } th { font: bold 16px "微软雅黑"; color: #fff; } td { font: 14px "微软雅黑"; } tbody tr { background-color: #f0f0f0; } tbody tr:hover { cursor: pointer; background-color: #fafafa; } </style> </head> <body> <div class="wrap"> <table> <thead> <tr> <th> <input type="checkbox" name="" id="j_cbAll"/> </th> <th>菜名</th> <th>饭店</th> </tr> </thead> <tbody id="j_tb"> <tr> <td> <input type="checkbox"/> </td> <td>红烧肉</td> <td>美食家</td> </tr> <tr> <td> <input type="checkbox"/> </td> <td>西红柿炒鸡蛋</td> <td>美食家</td> </tr> <tr> <td> <input type="checkbox"/> </td> <td>红烧狮子头</td> <td>美食家</td> </tr> <tr> <td> <input type="checkbox"/> </td> <td>日式肥牛</td> <td>美食家</td> </tr> </tbody> </table> </div> <script src="common.js"></script> <script> var btnAll = $$("j_cbAll"); // 总按钮 var tBody = $$("j_tb"); var inputs = tBody.getElementsByTagName("input"); // 给总按钮注册事件 控制下面的每一个小按钮和总按钮保持一致 btnAll.onclick = function(){ for(var i=0;i<inputs.length;i++){ inputs[i].checked =btnAll.checked;// 让总按钮的状态和每一个按钮一致 } } // 当我们点击当前按钮的时候,要判断 一下其它按钮的状态,如果所有的都选中了,则总按钮也选中 // 如果下面的按钮,有一个不选中的话,则总按钮也不选中 // 点击当前按钮,判断一下其它按钮 for(var j=0;j<inputs.length;j++){ inputs[j].onclick = function(){ // 设置一个标识,为true状态 var isBtnAll=true; //假设总按钮默认是选中的状态 for(var k=0;k<inputs.length;k++){ if(!inputs[k].checked){ // 临界点就是如果有一个不选中的话,则总的也不选中, isBtnAll = false; // 让总按钮的标识也是一个False的状态 break;//跳出当前循环 } // 假设都选中了 } btnAll.checked = isBtnAll; //总的按钮的状和标识是一致的 } } </script> </body> </html>
上述代码中,我保留了比较多的注释,是为了运行时能看着方便。这段代码实现的主要功能是点击最上面的按钮时实现全选,在点击一次则变成全不选。而下面几个选择框中,如果有一个是不选中的话,那么全选按钮也是不选中状态的,而下面的按钮如果都选中了,那么全选按钮也是选中的状态。首先我们就要来做第一个按钮,也就是全选和不全选。点击总按钮时,循环遍历下面所有的按钮,使得下面所有的按钮跟全选按钮的状态保持椅子,这样就能实现全选和不全选了。之后,就是下面小按钮点击的事件了。循环遍历每个小按钮给他们添加鼠标点击事件,当点击一个按钮时触发匿名函数中代码,循环遍历每个小按钮判断他们的状态,如果有一个没有选中,那么总按钮也是不选中状态的,如果都处于选中状态了,那么总按钮也是选中状态了。这里,我们在循环外要设置一个标志来定义总按钮的属性,在循环过程中,只要有一个按钮时不选中状态,则这个标志变为false,总按钮变为不选中状态。
在前面点击按钮让对应内容区域显示的代码中,我提到过一个自定义属性的概念,自定义属性就是一个我们自己定义的属性,JavaScript很灵活,它允许我们自设置自定义属性。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="text" class="ip" id="txt" value="123" aa="456"/> <script> var txt = document.getElementById("txt"); txt.mm = "258"; // 是可以通过 JS来设置自定义属性的 console.log(txt.type); console.log(txt.id); console.log(txt.value); console.log(txt.aa); // JS只能获取标签对象的原有属性,无法获得自定义属性 console.log(txt.mm); // 通过对象.的方式是无法获得标签 元素的自定义属性的 console.log(txt.getAttribute("type")); console.log(txt.getAttribute("aa")); console.log(txt.getAttribute("id")); console.log(txt.getAttribute("value")); txt.setAttribute("lll", "789999"); // setAttribute来设置对象的属性 //txt.className = ""; // 只有属性了,属性值已经不存在了 txt.removeAttribute("class"); // 删除更彻底一些,将属性名也删除 </script> </body> </html>
不过,自定义属性通过对象加点再跟上属性名的方式是无法获取到元素的自定义属性的,而我们在js中自定义属性在页面中也是不会显示的。这时候,我们就要借助其他方法来获得和设置自定义属性。getAttribute()方法就可以获得标签中所有的属性,包括原有属性和自定义属性。那我们要如果给对象设置自定义属性呢,这时候,我们只要使用setAttribute()方法来给标签设置自定义属性,括号内填写的依次是属性名和属性值。同样的,我们也可以删除属性,比如我们想删除类这个属性,我们以前的做法是让类的值为空,不过这样只是设置了值为空,而不是删除了这个属性,而是用removeAttribute()则删除的更彻底一些,连属性名也是一同删除的。
最后,再来讲讲关于获得,设置和移除页面中节点的属性,在之前的文章中提到过,我们可以把整个HTML页面看成是由一个个节点组成的。节点跟节点之间存在有各种各样的关系,比如父子啊,兄弟啊。因此,DOM中也有关于获取节点的父子节点和兄弟节点的方法。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div class="box" id="box"> <ul id="ul"> <li>1111</li> <li>2222</li> <li id="li">3333</li> <li>4444</li> </ul> <p></p> </div> <script> var ul = document.getElementById("ul"); console.log(ul.parentNode); //直接获得ul的父级元素节点 var lis = ul.childNodes; // 获得所有的子节点,包括文本节点 for (var i = 0; i < lis.length; i++) { console.log(lis[i]); } console.log(lis.length); var lis2 = ul.children; // children只会获得元素节点 console.log(lis2.length); for (var i = 0; i < lis2.length; i++) { console.log(lis2[i]); } </script> </body> </html>
我们可以通过对象加点再跟一个parentNode的方式只会获取ul的父级节点。而通过对象加点再跟一个childNode的方式可以获得所有的子节点。也包括标签跟标签之间的空白节点。而通过对象加点再跟一个children的方式,获取的则是对象所有元素子节点。
标签:
原文地址:http://www.cnblogs.com/wqc5730/p/5747679.html