我们首先要明白,我们给页面添加效果用到的js到底是什么?js其实包含三部分:dom 文档对象模型 bom 浏览器对象模型ecmascript 语法 简称(es)我们的效果实现其实是用es语法操作dom和bom去实现我们的目的一张图表示我们js的处理方式还算是清晰吧,dom和bom可以看出就是桥梁的作用,实现html页面与es的结合,我们运用es语法去调用何处理dom、bom的接口就可以实现对html页面的显示处理。 看书是很乏味的,尤其js的书籍要不就是仅仅讲了一堆es语法,看完对做效果一脸茫然,要不就是从es讲到dom到bom,你看前面es语法就要用几个星期,已经让你无奈了,等看到dom也忘得差不多,最后还是一脸茫然!我们从dom开始,结合最简单的es语法,做对应处理,开始出发! 前言,dom就是文档对象模型,就是对html页面就是模型化,与html产生映射,1.dom-获取节点我们页面里假如有如下的html机构:
我是一个id节点
我是一个div节点我是一个div节点我是一个div节点
我是p节点,在id下
我是p节点,在id下
我是p节点,在id下
我是类名节点
我们要做的就是获取标签里面的内容dom的接口方法就是: node.innerHTML (这个属性既可以获取节点内容,又可以赋值内容)我们要输出这些内容js 提供的方法 alert() (弹框形式显示内容) dom提供的基本获取接口:document.getElementById("id") 通过id查找,id具有唯一性,返回一个节点元素document.getElementsByTagName("tagname") 通过标签名查找,返回多个元素(伪数组),一个页面加入对div,会出现多个document.getElementsByTagName("*") 通过标签名的通配符查找,返回所有元素(伪数组)document.getElementById("id") .document.getElementsByTagName("tagname") 配合查找,找到指定id的元素,在当前元素下,查找指定标签名元素返回以上方法是最常用方法,兼容所低级ie和所有高级浏览器,document.querySelectorAll(".demo4 a") 通过css选择器获取方法,会获取叫demo4类名元素下的所有a元素,返回所有document.querySelector("div") 通过css选择器获取方法,会获取所有div元素,返回第一个上面两个方法兼容ie8以上,不对低级ie支持, 相关知识:我们提到的伪数组,和数组的区别就是根不是数组,其他表现完全与数组相同我们新建一个数组 var arr=[123,456,789] 这就是数组的形式。伪数组表现一样,只不过是里面内容换成了节点元素 [node1,node2,node3]数组具有length属性 alert(arr.length) 会返回长度为3;同样,数组作为一个集合,具有索引匹配,我们alert(arr[0]) ;alert(arr[1]) ;alert(arr[2]);会一次得到 123, 456 ,789这样就太麻烦了,不断就是alert,我们可以采用for循环for 循环结构for(var i=0;i标题1标题2标题3
内容1
内容2
内容3
js代码:window.onload=function(){ var list=document.getElementById("list"); var listspan=list.getElementsByTagName("span") var con=document.getElementById("con"); var condiv=con.getElementsByTagName("div") for(var i=0;iaspanjs:window.onload=function(){ var ctarget=document.getElementById("ctarget"); ctarget.onclick=function(event){ var evtcon=event.target; if(evtcon.innerHTML=="a"){ alert("点击了子元素a") }else if(evtcon.innerHTML=="span"){ alert("点击了子元素span") }else{ alert("我是div") } }; }; 相关:if判断语句if(){}else{} if(){}else if(){}else{}如果成立,执行下面代码,其他,执行下面代码,简单的一看就能理解我们还是分析这段js 点击事件,我们获取event对象的target属性,得到一个最小触发元素假如我们不做上面处理,那就要写三个单击事件,对div 对a 对 span我们通过判断event.target给父元素加一个事件,就做到了要加3个事件的处理,大大简化的代码, 通过页面测试,我们也得到,点击子元素,会淡出判断下的内容,得到target属性返回一个最小触发事件元素 提到事件,我们就必须说到捕获和冒泡元素+事件+方法,的事件是怎样元素上触发的:捕获:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)冒泡:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。针对处理,我们要用监听事件函数,添加事件ele.addEventListener('click',function,true)第三个参数若是true,则表示采用事件捕获,若是false,则表示采用事件冒泡。我们有一个这样结构:
都添加click事件,当你使用事件捕获时,父级元素先触发,子级元素后触发,即div先触发,p后触发。当你使用事件冒泡时,子级元素先触发,父级元素后触发,即p先触发,div后触发。document.documentElement指向html元素,可以得到根节点,我们做一个例子:html
点我
4564645
jswindow.onload=function(){ var fu=document.getElementById("fu"); var zi=document.getElementById("zi"); fu.addEventListener('click',function(){ zi.style.display="block" },false); document.documentElement.addEventListener('click',function(){ zi.style.display="none" },false); };这段js我们看原理,应该点击fu就让里面的儿子元素zi显示的,结果却没有显示,很不符合常理,我们添加事件用的是冒泡触发我们更改如下window.onload=function(){ var fu=document.getElementById("fu"); var zi=document.getElementById("zi"); fu.addEventListener('click',function(){ zi.style.display="block" },true); document.documentElement.addEventListener('click',function(){ zi.style.display="none" },true); };监听事件改为true,发现可以了,这就是我们理想的显示效果了 我们先看设置为false的冒泡触发的,第一段不可行代码,fu元素先执行事件,让后冒泡,一定会到html上,它属于html的子元素。发现html也加了事件,这个事件是第二次定义,自然踢掉了第一次fu定义的事件,就相当于给fu添加事件,触发的而方法是document.documentElement的方法,自然就不显示了我们看第二段正确js;捕获处理,添加事件html往下需找,会下找到document.documentElement,然后找到fu,发现都有方法,那么第二次执行的fu运用方法替掉html的就正确执行了;总结冒泡和捕获事件执行机制:采用冒泡,从下往上,查找,父元素有同样事件时,采用父元素事件的处理方法采用捕获,从上往下,查找,父元素有同样事件时,采用子元素事件的处理方法不通过addEventListener添加的事件都是冒泡发生的,这回影响到我们的,导致一些问题我们会发现,dom为event提供了解决方法event.stopPropagation() 阻止冒泡event.preventDefault() 阻止默认我们对第一段不执行代码修改为直接事件添加处理window.onload=function(){ var fu=document.getElementById("fu"); var zi=document.getElementById("zi"); fu.onclick=function(event){ zi.style.display="block"; } document.documentElement.onclick=function(){ zi.style.display="none" }; }; 点击没有显示,和第一段代码一个效果,我们加上阻止冒泡处理event.stopPropagation() ,代码如下window.onload=function(){ var fu=document.getElementById("fu"); var zi=document.getElementById("zi"); fu.onclick=function(event){ zi.style.display="block"; event.stopPropagation() } document.documentElement.onclick=function(){ zi.style.display="none" }; };直接监听事件也出来,万岁,我们得出结论通过监听方法加事件可以控制是冒泡还是捕获触发事件直接添加都是冒泡触发事件还有一个阻止默认,这有什么用处,我们在demo一个a标签,点击应该会链接到一个页面,没连接到,你是没联网我是连接我想点击它,不跳转,就如同点了span一样,我们给a添加click事件,加上event.preventDefault()window.onload=function(){ var lia=document.getElementById("lia"); lia.onclick=function(event){ //event.preventDefault() } };a标签默认链接跳转不行了,原来作用就是在这个,其实这个用处还是很大的,在一些特殊处理,根据权限确实要限制用户除了这个,还有一个办法,那就是window.onload=function(){ var lia=document.getElementById("lia"); lia.onclick=function(event){ return false; } };执行方法返回一个false,执行出错,当然也不会跳了,这个比上个好,写起来简单得多 3.可拖拽的登陆框onmousedown 鼠标按下onmousemove 鼠标移动onmouseup鼠标抬起这三个兄弟事件,我们按思路走一次,这是一个组合处理,把click进行了具体的拆分,我们按下某个元素,然后拖动鼠标,元素跟着鼠标动,鼠标抬起,元素就放置在鼠标离开位置,ok,这个思路我们可以做一个例子了,改变位置,一定要用到对元素的left和top的处理,跟着鼠标,当然还要用到事件对象的left和top了这些还不够,我们需要把三个事件链接在一起,我们可以这样处理,var isd=0;初始化的时候,在按下,isd=1;移动isd=1,抬起isd=0;这样每次组合事件处理就链接一起了我们发现,通过ele.style.left获取的位置是带有px的,但是event.clientX不带单位,真是遇到狗了我们获取是不要带px,我们可以用另一种方式,dom的apiele.offsetLeft;ele.offsetTop;同样可以获取到left和top并且去掉了单位,html
登录
密码
jswindow.onload=function(){ var drag=document.getElementById("drag"); var isd=0; var elex=0; var eley=0; drag.onmousedown=function(event){ isd=1; elex=event.clientX-drag.offsetLeft; eley=event.clientY-drag.offsetTop; }; drag.onmousemove=function(event){ if(isd==1){ var evx=event.clientX; var evy=event.clientY; var cx=evx-elex; var cy=evy-eley; drag.style.left=cx+"px"; drag.style.top=cy+"px"; }else{} }; drag.onmouseup=function(event){ isd=0; }; };完美的拖拽实现了,我们获取元素的left和top没有用drag.style.left的方式获取,而是用了drag.offsetLeftdom针对left、top、width、heigth扩展api: 都是无单位获取 ele.offsetLeft 获取元素可见left值,针对对父容器带偏移量,就是margin和paddingele.offsetTopele.offsetWidth 获取元素可见宽度ele.offsetHeight ele.clientLeft 获取元素可见left针 与父容器无关ele.clientTopele.clientWidth 获取元素可见宽度,加偏移ele.clientHeight ele.scrollLeft 获取元素滚动条的left值,裁剪宽 与父元素无关 可赋值ele.scrollTop 可赋值ele.scrollWidth 获取元素加上滚动条的总宽度ele.scrollHeight ele.getBoundingClientRect().top 元素上边距离页面上边的距离ele.getBoundingClientRect().right 元素右边距离页面左边的距离ele.getBoundingClientRect().bottom 元素下边距离页面上边的距离ele.getBoundingClientRect().left 元素左边距离页面左边的距离 针对html节点和body节点,dom内有写好的对象document.documentElement 指代html元素 页面根元素document.body 指代body元素,html4.0以前根元素 我们已经知道通过ele.style可以获取样式和赋值样式,同样与其相关还有专门获取样式的api 带单位ele.currentStyle.width 获取某个样式 低级ie和iegetComputedStyle(ele,false).width 获取某个样式 主流浏览器同样我把style的接口也列出来ele.style.width 获取元素样式ele.style.width="10px" 给元素样式赋值,要带单位ele.style.cssText="height:10px;width:20px;" 给元素样式赋值,采用样式表方式还需要注意的就是,对于有-的样式,我们要去掉-,并且把-后面的第一个字母大写,如:ele.style.marginTop="20px" 我们总结和所有对元素宽高,上下位置的api还有对样式的处理api,我们接下来要做一个实例,简单运用:4.我们把页面,滑动到最底部,点击一个按钮,页面回到顶部;一个高度2000px的div,下面一个回到顶部按钮,点击按钮,回到顶部就是根元素的滚动条变为0;html
回到顶部jswindow.onload=function(){ var top=document.getElementById("top"); top.onclick=function(){ document.documentElement.scrollTop=0; }; }; 原理实现,document.documentElement指代html,页面过长,会导致html出现滚动条,通过把html元素的scrollTop设置为0,实现回到顶部,scrollTop可取值,可赋值,这样在强硬了,我们一样缓慢回到顶部,从当前,经过ns回到0;就是animation 底部top =》 顶部topdom中我们会间接的介绍到一些bom和es的东西,不过很少,很简单window.onload=function(){ var top=document.getElementById("top"); var dibu=null; var dong=null; top.onclick=function(){ dibu=document.documentElement.scrollTop; dong=setInterval(function(){ dibu=dibu-5; if(dibu<=0){ document.documentElement.scrollTop=0; clearInterval(dong); }else{ document.documentElement.scrollTop=dibu; }; },10); }; };setInterval(fun,time) 第一个参数调用函数,第二个执行时间 方法返回一个id,clearInterval(id) 清除定时器,id是定时器返回值执行原理就是点击返回,执行间隔函数,每次对全局变量的top值就行-10处理。并且把改变的top值赋值给html的scrollTop,没10秒改变一次滚动条位置 3.dom-node(节点操作)事件一部分,我们可以说倾注了大量的研究每个就是对元素and几点就行操作通过前两部分的学习,我们了解了js的基本处理流程1.对象+事件+方法 ele.onclick=function(){ }2.对象+方法 ele.innerHTML 基本api节点就是指代html的各种元素如html标签就是根元素, document.documentElement表示同样我们通过获取id查找,获通过标签名得到的元素也是节点,都是标签节点节点具有类型性: 获取节点类型api:node.nodeType 为1: 节点为元素 如div 标签 我们的主要应用api为2; 节点为属性为3:节点为文本 获取名字:node.nodeName 主要针对类型为1的元素节点,获取标签名,返回为为大写 添加属性,获取属性api: 主要操作都是针对元素节点,类型为1elenode.setAttribute("aa","123") 设置节点属性aaelenode.getAttribute("aa","123") 获取节点属性aa除了通过属性方法对节点操作,还有直接操作方式,如:elenode.aa 获取节点属性aa元素节点(标签)除了已经提供好的属性的设置获取,我们还可以自定义属性,如上面的aa属性,原生属性设置和获取input.checked input添加checked属性img.width="200" 图片宽度属性设置为200div.id="a1" 给div加一个id属性等属性的处理 对于节点类型为1的元素,还具有标签名属性,api:node.tagName 获取节点的标签名 对于节点类型为1的元素,还具有类名属性,api:node.className 获取和设置标签的类名 非常常用,我们添加一个class采用新样式都是靠这个apinode.className="aa" 设置标签的类名为aanode.className 获取标签的类名 总结:上面我们可以判断节点的类型,主要为1,我们操作元素,可以添加属性,设置属性,自定义属性,获取类名,添加类型,获取元素标签名,这些就很足够了 节点关系api我们写一句获取元素代码jsvar id1=document.getElementById("id1");html
1
2
3-1
3-2-1
3-3
4
5
我们通过js,找到了id为id1的div节点,但是我们想要获取相关的兄弟,父亲,孩子节点,通过第一部分是要很麻烦的处理dom为我们这些node关系,提供了更全面的关系节点接口node.childNodes 针对上面代码返回7,包含空白文档,实际应该5个node.firstChild 第一个和最后一个子节点都是文本节点,可以输出nodeType测试 返回3 node.lastChild node.parentNode 获取父节点,单一,父元素只会有一个node.nextSibling 获取兄弟节点,下一个 要想输出,删除标签间空格node.previousSibling 获取兄弟节点,上一个这些节点操作除了父节点,其他都受到空格文本节点的影响,我们需要获取后,通过if都判断nodeType为1做元素处理我们还是做tab切换,这次通过节点关系去处理:html
标题1标题2标题3
内容1
内容2
内容3
jswindow.onload=function(){ var list=document.getElementById("list"); var listspan=list.childNodes; var con=document.getElementById("con"); var condiv=con.childNodes; for(var i=0;ijswindow.onload=function(){ var a1=document.getElementById("a1"); var createle=document.createElement("p"); createle.innerHTML="我是插入的p内容"; a1.appendChild(createle); var a2=document.getElementById("a2"); var creattext=document.createTextNode("我是文本节点"); a2.appendChild(creattext); }我们测试代码,创建元素和文本成立,并且通过 appendCild作() 为子节点插入到指定元素下针对 insertBefore api:html
123
456
jswindow.onload=function(){ var a2=document.getElementById("a2"); var createle=document.createElement("p"); createle.innerHTML="我是插入的p内容"; a2.insertBefore(createle,null); }执行代码,创建的的节点作为兄弟元素插入,调用外部插入需要两个参数,第一个是插入的节点,第二个是插入节点的子元素,可以为null;测试removeChild api:html
我是i子节点111
我是i子节点222
jswindow.onload=function(){ var a1=document.getElementById("a1"); var z1=document.getElementById("z1"); a1.removeChild(z1) }删除节点,是删除指定子节点,参数是必须明确找到的一个子节点替换子节点和复制节点 api:html
我是i子节点111
我是i子节点222
ccc
jswindow.onload=function(){ var a1=document.getElementById("a1"); var z1=document.getElementById("z1"); var newnode=document.createElement("a"); newnode.innerHTML="aaa"; a1.replaceChild(newnode,z1) ; var a2=document.getElementById("a2"); var c1=document.getElementById("c1"); var clonenode=c1.cloneNode(true); clonenode.id="c2"; a2=appendChild(clonenode);}替换方法需要两个参数,第一个新节点,第二个被替换子节点复制操作,复制得到相同节点,id具有唯一性,对id属性重新复制判断子节点是否存在方法 hasChildNodes api:html
我是i子节点111
jswindow.onload=function(){ var a1=document.getElementById("a1"); var z1=document.getElementById("z1"); alert(a1.hasChildNodes()); alert(z1.hasChildNodes());}父节点调用,有子节点返回true,没有false。无需参数总结:基本节点处理,类型判断(为1),属性设置、获取,类名获取、设置,标签名获取节点关系,父亲,兄弟,孩子操作处理,创建,插入,替换,删除,复制,有无子节点我们使用节点关系获取子节点,下一个、上一个兄弟节点,最后子节点,发现发挥的节点,都是空格文本节点我们要做的就是对html元素的处理,就是node的类型为1,才是我们想要的也就是,获取子节点,获取的子节点都是元素标签兄弟节点也要是元素标签节点,这样才能为我们所工作我们以这些节点操作为核心,用节点类型为1作为判断依据,返回一个数组(存放元素集合)为结果,做函数的封装处理我们前面介绍了,获取html元素和body接口,我们的页面还会有一些很特殊的标签,需要在、提供特殊接口去处理,如:iframeiframe回载入一个html页面作为子页面,dom提供的接口获取:ifrmaeele.contentDocument 找到iframe,调用属性得到子html页面,htmljswindow.onload=function(){ var if1=document.getElementById("if1"); alert(if1.contentDocument.documentElement.offsetHeight); }会弹出内部html的高度,这段代码不要再谷歌测试,谷歌需要在服务器上运行才可以,要做http协议的