下面我们接着介绍创建节点。
创建节点,插入节点的方式,就好像是买一个大袋子,一个大袋子里装着一些小袋子,小袋子里分别装着不同的东西。
我们来看看代码就一目了然了:
<script type="text/javascript"> //新创建一个元素节点,并把该节点添加为文档中指定节点的子节点 window.onload = function() { //新创建一个元素节点,返回值为指向元素节点的引用 //<li></li> var liNode = document.createElement("li"); //新创建一个文本节点 var textNode = document.createTextNode("华盛顿"); //将文本节点添加到li的子节点 //<li>华盛顿</li> liNode.appendChild(textNode); var cityNode = document.getElementById("city"); //新添加一个子节点,该子节点将会被添加到最后的位置 cityNode.appendChild(liNode); } </script>
大袋子(city)里装着很多小袋子(li),小袋子里装着不同的东西(不同的城市名字的文本),没错吧?很简单。
难道JavaScript只能支持这么low的做法吗?当然不是,还可以在现有已经存在的节点中互换双方的位置。当然,需要一个中间变量做转换。
代码如下:
<script type="text/javascript"> window.onload = function() { /*只能实现单向移动,被覆盖的节点还没拷贝 var bjNode = document.getElementById("bj"); var newNode = document.createElement("li"); var cityNode = document.getElementById("city"); //replaceChild()方法可以实现将"红警"移动到"北京" cityNode.replaceChild(newNode, bjNode); */ /* var bjNode = document.getElementById("bj"); var cityNode = document.getElementById("city"); var hjNode = document.getElementById("hj"); var gameNode = document.getElementById("game"); //先将北京节点拷贝下来 var tempNode = bjNode.cloneNode(true); gameNode.replaceChild(tempNode, hjNode); cityNode.replaceChild(hjNode, bjNode); */ var bjNode = document.getElementById("bj"); var hjNode = document.getElementById("hj"); replaceEach(bjNode, hjNode); } //自定义互换两个节点的函数 function replaceEach(aNode, bNode) { //1.获取aNode和bNode的父节点,使用parentNode属性 var aParent = aNode.parentNode; var bParent = bNode.parentNode; //当父节点存在的情况下才进行互换 if (aParent && bParent) { //2.克隆aNode var aNode2 = aNode.cloneNode(true); //3.分别调用aNode的父节点和bNode的父节点的peplaceChild()实现互换 bParent.replaceChild(aNode2, bNode); aParent.replaceChild(bNode, aNode); } } </script>
下面我们要介绍一下弹出可以选择是和否的对话框,也就是confirm()方法了。
练习需求:为每一个li节点添加一个confirm(),若确定,则删除,结合我们的removeChild()方法,这个练习so easy。
代码如下:
<script type="text/javascript"> //为每一个li节点添加一个confirm(),若确定,则删除 window.onload = function() { /* //测试:removeChild():删除节点 var cityNode = document.getElementById("city"); alert(cityNode.parentNode); //通过调用父节点的removeChild()来完成,更加快捷、方便 cityNode.parentNode.removeChild(cityNode); */ var liNodes = document.getElementsByTagName("li"); var length = liNodes.length; for (var i = 0; i < length; i++) { liNodes[i].onclick = function() { //confirm()方法会返回一个boolean值,选择确定未true,取消为false var flag = confirm("确定要删除\"" + this.innerHTML + "\"吗?"); if (flag) { this.parentNode.removeChild(this); } } } } </script>
JavaScript还提供了insertBefore()方法,允许我们可以将某节点插入到指定节点的前面。
代码如下:
//把#hj插入到#bj的前面 var cityNode = document.getElementById("city"); var bjNode = document.getElementById("bj"); var hjNode = document.getElementById("hj"); cityNode.insertBefore(hjNode, bjNode);
但是并没有提供insertAfter()方法。那我们就自定义一个吧!
思路是这样的:先检查指定节点是否为父节点的最后一个节点。如果是,那就直接appendChild(),因为这个方法默认放到最后;如果不是,那么就获取下一个节点,也就是.nextSibling()方法,然后再使用insertBefore()方法。
代码如下:
<script type="text/javascript"> window.onload = function() { var bjNode = document.getElementById("bj"); var hjNode = document.getElementById("hj"); insertAfter(hjNode, bjNode); } //把newNode插入到refNode的后面 function insertAfter(newNode, refNode) { //1.验证refNode是否为其父节点的最后一个节点 var parentNode = refNode.parentNode; if (parentNode) { var lastNode = parentNode.lastChild; if (lastNode == refNode) { //2.若是,则直接使用父节点的appendChild()将其插入到最后 parentNode.appendChild(newNode); } //3.若不是,则先获取refNode的下一个节点,再使用insertBefore()方法插入 else { parentNode.insertBefore(newNode, refNode.nextSibling); } } } </script>
下面我们要做几个练习,HTML文档如下:
<p>你喜欢哪个城市?</p> <ul id="city"> <li id="bj">北京</li> <li>上海</li> <li>东京</li> <li>首尔</li> </ul> <br> <br> <p>你喜欢哪款单击游戏?</p> <ul id="game"> <li id="hj">红警</li> <li>实况</li> <li>魔兽</li> <li>星际</li> </ul> <br> <br> <input type="radio" id="myCity" name="myChoose" value="city" />城市 <input type="radio" id="myGame" name="myChoose" value="game" />游戏 <p> name:<input type="text" id="name" name="name" /> </p> <input type="submit" id="mySubmit" name="mySubmit" value="submit" />
需求如下:需求1:点击submit按钮时,检查是否选择type,若没有选择就给出提示:“请选择类型”;
检查文本框中是否有输入(可以去除前后空格),若没有输入,则给出提示:“请输入内容”;
若检查都通过,则在相应的ul节点中添加对应的li节点;
需求2:使包括新增的li都能响应onclick事件,弹出li的文本值。
根据需求的描述,我们可以知道,其实所有的事件触发都在button上,那么就可以将所有的逻辑判断都加入到button上。
代码如下:
<script type="text/javascript"> window.onload = function() { function showContent(liNode) { alert(liNode.innerHTML); } var liNodes = document.getElementsByTagName("li"); var liLength = liNodes.length; for (var i = 0; i < liLength; i++) { liNodes[i].onclick = function() { showContent(this); } } //获取到按钮,并添加事件 var btn = document.getElementById("mySubmit"); btn.onclick = function() { //根据组名获取是否被选中的条件 var types = document.getElementsByName("myChoose"); var typeVal = null; var name = document.getElementById("name"); var length = types.length; //判断单选按钮是否被选中 for (var i = 0; i < length; i++) { if (types[i].checked) { typeVal = types[i].value; break; } } if (!typeVal) { alert("请选择类型"); return; } //判断用户是否输入 if (!name.value) { alert("请输入内容"); return; } //都通过的情况将添加一条li var li = document.createElement("li"); //获取文本框的内容 var text = document.createTextNode(name.value); //将文本框的内容添加到li li.appendChild(text); li.onclick = function() { showContent(this); } //将li添加到typeVal指定的ul var ulNode = document.getElementById(typeVal); ulNode.appendChild(li); } } </script>
新的需求如下:需求:为所有的li节点添加onclick响应函数;
实现city子节点和game子节点对应位置的元素的互换。
思路是这样的:根据标签名获取到所有的li节点,这样一来,li就在一个数组里面有属于自己的下标了。根据提供的HTML文档,我们可以让(0,1,2,3)和+4的交换,让(4,5,6,7)和-4的交换。
交换结束之后,我们不仅仅是交换节点内容,我们还需要重新赋予onclick事件,还需要将新的下标赋予它。
代码如下:
<script type="text/javascript"> window.onload = function() { var liNodes = document.getElementsByTagName("li"); var length = liNodes.length; for (var i = 0; i < length; i++) { //使用index储存当前节点的下标,因为在触发事件的时候i的值已经是超过length的那个值了 liNodes[i].index = i; liNodes[i].onclick = function() { var targetIndex = 0; if (this.index < 4) { targetIndex = this.index + 4; } else { targetIndex = this.index - 4; } replaceEach(this, liNodes[targetIndex]); } } //显示为8,没有局部变量这一说 //alert(i); } function replaceEach(aNode, bNode) { var aParent = aNode.parentNode; var bParent = bNode.parentNode; if (aParent && bParent) { //拷贝的时候并未将事件、index拷贝 var aNode2 = aNode.cloneNode(true); //alert(aNode.index); //alert(aNode2.index); //alert(bNode.index); //克隆aNode的同时,把onclick事件也复制 aNode2.onclick = aNode.onclick; aNode2.index = bNode.index; bNode.index = aNode.index; bParent.replaceChild(aNode2, bNode); aParent.replaceChild(bNode, aNode); } } </script>
很简单吧!
下面我们又来一个一份新的HTML文档,文档如下:
你爱好的运动是? <input type="checkbox" id="checkedAll" />全选/全不选 <br /> <input type="checkbox" name="items" value="足球" />足球 <input type="checkbox" name="items" value="篮球" />篮球 <input type="checkbox" name="items" value="排球" />排球 <input type="checkbox" name="items" value="乒乓球" />乒乓球 <br /> <input type="button" id="btnAll" value="全选" /> <input type="button" id="btnNo" value="全不选" /> <input type="button" id="checkedRev" value="反选" /> <input type="button" id="send" value="提交" />
一看这份文档,我们第一反应肯定是与按钮事件响应有关了。
需求:当点击id为checkedAll的按钮时,先检查下面的爱好选择做出选择:如果爱好全部被选择,那么checkedAll按钮要做的事情就是“全不选”;否则就是“全选”功能。
下面的button按钮根据名字就可以得知了。
每当爱好全部被打上钩时,checkedAll按钮也要被打上钩;只要不满足前面的条件,checkedAll按钮不能被打上钩。
看上去很绕,其实理清了思路,非常简单。需求正好就是我们的思路方向。
代码如下:
<script type="text/javascript"> window.onload = function() { var checkedAll = document.getElementById("checkedAll"); var items = document.getElementsByName("items"); var length = items.length; checkedAll.onclick = function() { var flag = 0; for (var i = 0; i < length; i++) { if (items[i].checked) { //每当一个选项已经被选中时就加1 flag += 1; } } //只有当全部选项都被选中时,点击按钮的效果才是“全不选” if (flag == length) { for (var j = 0; j < length; j++) { items[j].checked = false; } //记得把按钮本身的状态切换成一致,否则将会出现按钮本身未打钩而爱好的选项全打钩或者反过来的“灵异”现象 this.checked = false; } //其余情况下,都是“全选” else { for (var k = 0; k < length; k++) { items[k].checked = true; } this.checked = true; } } for (var l = 0; l < length; l++) { //给所有的爱好按钮增加事件 items[l].onclick = function() { check(); } } var btnAll = document.getElementById("btnAll"); btnAll.onclick = function() { for (var i = 0; i < length; i++) { items[i].checked = true; } check(); } var btnNo = document.getElementById("btnNo"); btnNo.onclick = function() { for (var i = 0; i < length; i++) { items[i].checked = false; } checkedAll.checked = false; } var checkedRev = document.getElementById("checkedRev"); checkedRev.onclick = function() { for (var i = 0; i < length; i++) { if (items[i].checked) { items[i].checked = false; } else { items[i].checked = true; } } check(); } var send = document.getElementById("send"); send.onclick = function() { for (var i = 0; i < length; i++) { if (items[i].checked) { alert(items[i].value); } } } //当所有爱好都打钩时,全选按钮也打上钩,否则就不打钩 function check() { var myFlag = 0; for (var m = 0; m < length; m++) { if (items[m].checked) { myFlag += 1; } } if (myFlag == length) { checkedAll.checked = true; } else { checkedAll.checked = false; } } } </script>
最后一份HTML文档从天而降。文档如下:
<p align="center">添加新员工</p> <table align="center"> <tr> <td>name:<input type="text" id="name" name="name" /></td> <td>email:<input type="text" id="email" name="email" /></td> <td>salary:<input type="text" id="salary" name="salary" /></td> </tr> </table> <p align="center"> <input type="button" id="add" name="add" value="新增" /> </p> <hr> <table id="employeeTable" align="center" border="1" cellpadding="5" cellspacing="0"> <tr> <th>name</th> <th>Email</th> <th>Salary</th> <th></th> </tr> <tr> <td>Tom</td> <td>[email protected]</td> <td>5000</td> <td><input type="submit" name="delete" value="Delete" /></td> </tr> <tr> <td>Mary</td> <td>[email protected]</td> <td>10000</td> <td><input type="submit" name="delete" value="Delete" /></td> </tr> </table>
需求:新增按钮:将员工的姓名、邮箱和薪水添加到表格中;
删除按钮:confirm()提示是否将"员工名字"信息删除?确定将整行员工信息删除,否则什么也不做。
新增按钮要做的事情,其实就是文章一开始要叙述的东西,也就是把某物品装进大袋子的事情。
删除按钮,其实只要能获取到它的父节点,也就解决了。
代码如下:
<script type="text/javascript"> window.onload = function() { //删除按钮触发的函数 function deleteInfo(node) { var currentTr = node.parentNode.parentNode; var name = currentTr.getElementsByTagName("td")[0]; var flag = confirm("是否将\"" + name.innerHTML + "\"信息删除?"); //当点击确定后触发事件 if (flag) { /* 第一个parentNode是td,第二个parentNode是tr,第三个parentNode是table 也就是说根据delete按钮所在的列所在的行所在的表格中删除掉整行(很拗口是吧?) */ node.parentNode.parentNode.parentNode .removeChild(node.parentNode.parentNode); } } var addBtn = document.getElementById("add"); addBtn.onclick = function() { //3个引用的value值可以获取到文本框的值 var nameNode = document.getElementById("name"); var emailNode = document.getElementById("email"); var salaryNode = document.getElementById("salary"); //获取table元素节点 var tableNode = document.getElementsByTagName("table")[1]; //创建一个tr节点,后面会添加到table元素节点中 var newTrNode = document.createElement("tr"); //创建一个td节点,后面会添加到tr元素节点中 var newName = document.createElement("td"); //创建一个文本节点,添加到td元素节点中 newName.appendChild(document.createTextNode(nameNode.value)); var newEmail = document.createElement("td"); newEmail.appendChild(document.createTextNode(emailNode.value)); var newSalary = document.createElement("td"); newSalary.appendChild(document.createTextNode(salaryNode.value)); var newDelete = document.createElement("td"); var newDeleteBtn = document.createElement("input"); newDeleteBtn.type = "button"; newDeleteBtn.name = "delete"; newDeleteBtn.value = "Delete"; //新创建的button也应该能触发删除函数 newDeleteBtn.onclick = function() { deleteInfo(this); } newDelete.appendChild(newDeleteBtn); newTrNode.appendChild(newName); newTrNode.appendChild(newEmail); newTrNode.appendChild(newSalary); newTrNode.appendChild(newDelete); tableNode.appendChild(newTrNode); } //为所有已经存在的删除按钮添加删除函数事件 var deleteNodes = document.getElementsByName("delete"); var length = deleteNodes.length; for (var i = 0; i < length; i++) { deleteNodes[i].onclick = function() { deleteInfo(this); } } } </script>
今天就到这里,我们下次再见!