我們首先要明白,我們給頁面添加效果用到的js到底是什么?js其實包含三部分:dom 文檔對象模型? ? ? bom 瀏覽器對象模型ecmascript 語法? 簡稱(es)我們的效果實現(xiàn)其實是用es語法操作dom和bom去實現(xiàn)我們的目的一張圖表示我們js的處理方式還算是清晰吧,dom和bom可以看出就是橋梁的作用,實現(xiàn)html頁面與es的結(jié)合,我們運用es語法去調(diào)用何處理dom、bom的接口就可以實現(xiàn)對html頁面的顯示處理。 看書是很乏味的,尤其js的書籍要不就是僅僅講了一堆es語法,看完對做效果一臉茫然,要不就是從es講到dom到bom,你看前面es語法就要用幾個星期,已經(jīng)讓你無奈了,等看到dom也忘得差不多,最后還是一臉茫然!我們從dom開始,結(jié)合最簡單的es語法,做對應(yīng)處理,開始出發(fā)! 前言,dom就是文檔對象模型,就是對html頁面就是模型化,與html產(chǎn)生映射,1.dom-獲取節(jié)點我們頁面里假如有如下的html機構(gòu):
我是一個id節(jié)點
我是一個div節(jié)點我是一個div節(jié)點我是一個div節(jié)點
我是p節(jié)點,在id下
我是p節(jié)點,在id下
我是p節(jié)點,在id下
我是類名節(jié)點
我們要做的就是獲取標(biāo)簽里面的內(nèi)容dom的接口方法就是:? node.innerHTML (這個屬性既可以獲取節(jié)點內(nèi)容,又可以賦值內(nèi)容)我們要輸出這些內(nèi)容js 提供的方法? alert()? (彈框形式顯示內(nèi)容) dom提供的基本獲取接口:document.getElementById("id")? ? 通過id查找,id具有唯一性,返回一個節(jié)點元素document.getElementsByTagName("tagname")? 通過標(biāo)簽名查找,返回多個元素(偽數(shù)組),一個頁面加入對div,會出現(xiàn)多個document.getElementsByTagName("*")? 通過標(biāo)簽名的通配符查找,返回所有元素(偽數(shù)組)document.getElementById("id") .document.getElementsByTagName("tagname")? 配合查找,找到指定id的元素,在當(dāng)前元素下,查找指定標(biāo)簽名元素返回以上方法是最常用方法,兼容所低級ie和所有高級瀏覽器,document.querySelectorAll(".demo4 a")? ? 通過css選擇器獲取方法,會獲取叫demo4類名元素下的所有a元素,返回所有document.querySelector("div")? 通過css選擇器獲取方法,會獲取所有div元素,返回第一個上面兩個方法兼容ie8以上,不對低級ie支持, 相關(guān)知識:我們提到的偽數(shù)組,和數(shù)組的區(qū)別就是根不是數(shù)組,其他表現(xiàn)完全與數(shù)組相同我們新建一個數(shù)組? var arr=[123,456,789]? ? 這就是數(shù)組的形式。偽數(shù)組表現(xiàn)一樣,只不過是里面內(nèi)容換成了節(jié)點元素 [node1,node2,node3]數(shù)組具有l(wèi)ength屬性 alert(arr.length)? 會返回長度為3;同樣,數(shù)組作為一個集合,具有索引匹配,我們alert(arr[0]) ;alert(arr[1]) ;alert(arr[2]);會一次得到 123, 456 ,789這樣就太麻煩了,不斷就是alert,我們可以采用for循環(huán)for 循環(huán)結(jié)構(gòu)for(var i=0;i標(biāo)題1標(biāo)題2標(biāo)題3
內(nèi)容1
內(nèi)容2
內(nèi)容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")? }? };? }; 相關(guān):if判斷語句if(){}else{} if(){}else if(){}else{}如果成立,執(zhí)行下面代碼,其他,執(zhí)行下面代碼,簡單的一看就能理解我們還是分析這段js? 點擊事件,我們獲取event對象的target屬性,得到一個最小觸發(fā)元素假如我們不做上面處理,那就要寫三個單擊事件,對div 對a 對 span我們通過判斷event.target給父元素加一個事件,就做到了要加3個事件的處理,大大簡化的代碼, 通過頁面測試,我們也得到,點擊子元素,會淡出判斷下的內(nèi)容,得到target屬性返回一個最小觸發(fā)事件元素 提到事件,我們就必須說到捕獲和冒泡元素+事件+方法,的事件是怎樣元素上觸發(fā)的:捕獲:事件從最上一級標(biāo)簽開始往下查找,直到捕獲到事件目標(biāo)(target)冒泡:事件從事件目標(biāo)(target)開始,往上冒泡直到頁面的最上一級標(biāo)簽。針對處理,我們要用監(jiān)聽事件函數(shù),添加事件ele.addEventListener('click',function,true)第三個參數(shù)若是true,則表示采用事件捕獲,若是false,則表示采用事件冒泡。我們有一個這樣結(jié)構(gòu):
都添加click事件,當(dāng)你使用事件捕獲時,父級元素先觸發(fā),子級元素后觸發(fā),即div先觸發(fā),p后觸發(fā)。當(dāng)你使用事件冒泡時,子級元素先觸發(fā),父級元素后觸發(fā),即p先觸發(fā),div后觸發(fā)。document.documentElement指向html元素,可以得到根節(jié)點,我們做一個例子: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我們看原理,應(yīng)該點擊fu就讓里面的兒子元素zi顯示的,結(jié)果卻沒有顯示,很不符合常理,我們添加事件用的是冒泡觸發(fā)我們更改如下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);? };監(jiān)聽事件改為true,發(fā)現(xiàn)可以了,這就是我們理想的顯示效果了 我們先看設(shè)置為false的冒泡觸發(fā)的,第一段不可行代碼,fu元素先執(zhí)行事件,讓后冒泡,一定會到html上,它屬于html的子元素。發(fā)現(xiàn)html也加了事件,這個事件是第二次定義,自然踢掉了第一次fu定義的事件,就相當(dāng)于給fu添加事件,觸發(fā)的而方法是document.documentElement的方法,自然就不顯示了我們看第二段正確js;捕獲處理,添加事件html往下需找,會下找到document.documentElement,然后找到fu,發(fā)現(xiàn)都有方法,那么第二次執(zhí)行的fu運用方法替掉html的就正確執(zhí)行了;總結(jié)冒泡和捕獲事件執(zhí)行機制:采用冒泡,從下往上,查找,父元素有同樣事件時,采用父元素事件的處理方法采用捕獲,從上往下,查找,父元素有同樣事件時,采用子元素事件的處理方法不通過addEventListener添加的事件都是冒泡發(fā)生的,這回影響到我們的,導(dǎo)致一些問題我們會發(fā)現(xiàn),dom為event提供了解決方法event.stopPropagation()? 阻止冒泡event.preventDefault()? 阻止默認(rèn)我們對第一段不執(zhí)行代碼修改為直接事件添加處理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" };? };直接監(jiān)聽事件也出來,萬歲,我們得出結(jié)論通過監(jiān)聽方法加事件可以控制是冒泡還是捕獲觸發(fā)事件直接添加都是冒泡觸發(fā)事件還有一個阻止默認(rèn),這有什么用處,我們在demo一個a標(biāo)簽,點擊應(yīng)該會鏈接到一個頁面,沒連接到,你是沒聯(lián)網(wǎng)我是連接我想點擊它,不跳轉(zhuǎn),就如同點了span一樣,我們給a添加click事件,加上event.preventDefault()window.onload=function(){ var lia=document.getElementById("lia");? lia.onclick=function(event){? ? //event.preventDefault()? }? };a標(biāo)簽?zāi)J(rèn)鏈接跳轉(zhuǎn)不行了,原來作用就是在這個,其實這個用處還是很大的,在一些特殊處理,根據(jù)權(quán)限確實要限制用戶除了這個,還有一個辦法,那就是window.onload=function(){ var lia=document.getElementById("lia");? lia.onclick=function(event){? ? return false; }? };執(zhí)行方法返回一個false,執(zhí)行出錯,當(dāng)然也不會跳了,這個比上個好,寫起來簡單得多 3.可拖拽的登陸框onmousedown 鼠標(biāo)按下onmousemove 鼠標(biāo)移動onmouseup鼠標(biāo)抬起這三個兄弟事件,我們按思路走一次,這是一個組合處理,把click進行了具體的拆分,我們按下某個元素,然后拖動鼠標(biāo),元素跟著鼠標(biāo)動,鼠標(biāo)抬起,元素就放置在鼠標(biāo)離開位置,ok,這個思路我們可以做一個例子了,改變位置,一定要用到對元素的left和top的處理,跟著鼠標(biāo),當(dāng)然還要用到事件對象的left和top了這些還不夠,我們需要把三個事件鏈接在一起,我們可以這樣處理,var isd=0;初始化的時候,在按下,isd=1;移動isd=1,抬起isd=0;這樣每次組合事件處理就鏈接一起了我們發(fā)現(xiàn),通過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; };? };完美的拖拽實現(xiàn)了,我們獲取元素的left和top沒有用drag.style.left的方式獲取,而是用了drag.offsetLeftdom針對left、top、width、heigth擴展api:? ? ? ? 都是無單位獲取 ele.offsetLeft? ? ? ? ? ? ? ? ? ? 獲取元素可見left值,針對對父容器帶偏移量,就是margin和paddingele.offsetTopele.offsetWidth? ? ? ? ? ? ? ? 獲取元素可見寬度ele.offsetHeight ele.clientLeft? ? ? ? ? ? ? ? ? ? ? ? 獲取元素可見left針? 與父容器無關(guān)ele.clientTopele.clientWidth? ? ? ? ? ? ? ? ? ? 獲取元素可見寬度,加偏移ele.clientHeight ele.scrollLeft? ? ? ? ? ? ? ? ? ? 獲取元素滾動條的left值,裁剪寬 與父元素?zé)o關(guān)? ? 可賦值ele.scrollTop? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 可賦值ele.scrollWidth? ? ? ? ? ? ? ? ? 獲取元素加上滾動條的總寬度ele.scrollHeight? ele.getBoundingClientRect().top? ? ? ? ? ? 元素上邊距離頁面上邊的距離ele.getBoundingClientRect().right? ? ? ? ? 元素右邊距離頁面左邊的距離ele.getBoundingClientRect().bottom? ? ? 元素下邊距離頁面上邊的距離ele.getBoundingClientRect().left? ? ? ? ? ? 元素左邊距離頁面左邊的距離 針對html節(jié)點和body節(jié)點,dom內(nèi)有寫好的對象document.documentElement? ? ? 指代html元素 頁面根元素document.body? ? ? ? ? ? ? ? ? ? ? ? ? 指代body元素,html4.0以前根元素 我們已經(jīng)知道通過ele.style可以獲取樣式和賦值樣式,同樣與其相關(guān)還有專門獲取樣式的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" 我們總結(jié)和所有對元素寬高,上下位置的api還有對樣式的處理api,我們接下來要做一個實例,簡單運用:4.我們把頁面,滑動到最底部,點擊一個按鈕,頁面回到頂部;一個高度2000px的div,下面一個回到頂部按鈕,點擊按鈕,回到頂部就是根元素的滾動條變?yōu)?;html
回到頂部jswindow.onload=function(){ var top=document.getElementById("top");? top.onclick=function(){? document.documentElement.scrollTop=0; };? ? }; 原理實現(xiàn),document.documentElement指代html,頁面過長,會導(dǎo)致html出現(xiàn)滾動條,通過把html元素的scrollTop設(shè)置為0,實現(xiàn)回到頂部,scrollTop可取值,可賦值,這樣在強硬了,我們一樣緩慢回到頂部,從當(dāng)前,經(jīng)過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)? 第一個參數(shù)調(diào)用函數(shù),第二個執(zhí)行時間 方法返回一個id,clearInterval(id)? ? ? ? ? 清除定時器,id是定時器返回值執(zhí)行原理就是點擊返回,執(zhí)行間隔函數(shù),每次對全局變量的top值就行-10處理。并且把改變的top值賦值給html的scrollTop,沒10秒改變一次滾動條位置 3.dom-node(節(jié)點操作)事件一部分,我們可以說傾注了大量的研究每個就是對元素and幾點就行操作通過前兩部分的學(xué)習(xí),我們了解了js的基本處理流程1.對象+事件+方法? ? ? ? ele.onclick=function(){ }2.對象+方法? ? ? ? ? ? ? ? ele.innerHTML 基本api節(jié)點就是指代html的各種元素如html標(biāo)簽就是根元素, document.documentElement表示同樣我們通過獲取id查找,獲通過標(biāo)簽名得到的元素也是節(jié)點,都是標(biāo)簽節(jié)點節(jié)點具有類型性: 獲取節(jié)點類型api:node.nodeType 為1: 節(jié)點為元素? 如div 標(biāo)簽? 我們的主要應(yīng)用api為2; 節(jié)點為屬性為3:節(jié)點為文本 獲取名字:node.nodeName? ? ? ? 主要針對類型為1的元素節(jié)點,獲取標(biāo)簽名,返回為為大寫 添加屬性,獲取屬性api: 主要操作都是針對元素節(jié)點,類型為1elenode.setAttribute("aa","123")? ? ? ? ? ? ? 設(shè)置節(jié)點屬性aaelenode.getAttribute("aa","123")? ? ? ? ? ? ? 獲取節(jié)點屬性aa除了通過屬性方法對節(jié)點操作,還有直接操作方式,如:elenode.aa? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 獲取節(jié)點屬性aa元素節(jié)點(標(biāo)簽)除了已經(jīng)提供好的屬性的設(shè)置獲取,我們還可以自定義屬性,如上面的aa屬性,原生屬性設(shè)置和獲取input.checked? ? ? ? input添加checked屬性img.width="200"? ? 圖片寬度屬性設(shè)置為200div.id="a1"? ? ? ? ? ? 給div加一個id屬性等屬性的處理 對于節(jié)點類型為1的元素,還具有標(biāo)簽名屬性,api:node.tagName? ? 獲取節(jié)點的標(biāo)簽名 對于節(jié)點類型為1的元素,還具有類名屬性,api:node.className? ? ? 獲取和設(shè)置標(biāo)簽的類名? ? ? ? 非常常用,我們添加一個class采用新樣式都是靠這個apinode.className="aa"? 設(shè)置標(biāo)簽的類名為aanode.className? ? ? ? ? ? 獲取標(biāo)簽的類名 總結(jié):上面我們可以判斷節(jié)點的類型,主要為1,我們操作元素,可以添加屬性,設(shè)置屬性,自定義屬性,獲取類名,添加類型,獲取元素標(biāo)簽名,這些就很足夠了 節(jié)點關(guān)系api我們寫一句獲取元素代碼jsvar id1=document.getElementById("id1");html
1
2
3-1
3-2-1
3-3
4
5
我們通過js,找到了id為id1的div節(jié)點,但是我們想要獲取相關(guān)的兄弟,父親,孩子節(jié)點,通過第一部分是要很麻煩的處理dom為我們這些node關(guān)系,提供了更全面的關(guān)系節(jié)點接口node.childNodes? ? ? ? ? ? ? ? 針對上面代碼返回7,包含空白文檔,實際應(yīng)該5個node.firstChild? ? ? ? ? ? ? ? ? 第一個和最后一個子節(jié)點都是文本節(jié)點,可以輸出nodeType測試 返回3 node.lastChild? ? ? ? ? ? ? ? ? node.parentNode? ? ? ? ? ? ? 獲取父節(jié)點,單一,父元素只會有一個node.nextSibling? ? ? ? ? ? ? ? 獲取兄弟節(jié)點,下一個? 要想輸出,刪除標(biāo)簽間空格node.previousSibling? ? ? ? ? 獲取兄弟節(jié)點,上一個這些節(jié)點操作除了父節(jié)點,其他都受到空格文本節(jié)點的影響,我們需要獲取后,通過if都判斷nodeType為1做元素處理我們還是做tab切換,這次通過節(jié)點關(guān)系去處理:html
標(biāo)題1標(biāo)題2標(biāo)題3
內(nèi)容1
內(nèi)容2
內(nèi)容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內(nèi)容";? ? ? ? ? a1.appendChild(createle);? ? ? ? var a2=document.getElementById("a2");? ? ? ? var creattext=document.createTextNode("我是文本節(jié)點");? ? ? ? ? a2.appendChild(creattext); }我們測試代碼,創(chuàng)建元素和文本成立,并且通過? appendCild作() 為子節(jié)點插入到指定元素下針對 insertBefore api:html
123
456
jswindow.onload=function(){? ? ? ? ? ? ? var a2=document.getElementById("a2");? ? ? ? var createle=document.createElement("p");? ? ? ? createle.innerHTML="我是插入的p內(nèi)容";? ? ? ? ? a2.insertBefore(createle,null); }執(zhí)行代碼,創(chuàng)建的的節(jié)點作為兄弟元素插入,調(diào)用外部插入需要兩個參數(shù),第一個是插入的節(jié)點,第二個是插入節(jié)點的子元素,可以為null;測試removeChild api:html
我是i子節(jié)點111
我是i子節(jié)點222
jswindow.onload=function(){? ? ? ? ? ? ? var a1=document.getElementById("a1");? ? ? ? var z1=document.getElementById("z1");? ? ? ? a1.removeChild(z1) }刪除節(jié)點,是刪除指定子節(jié)點,參數(shù)是必須明確找到的一個子節(jié)點替換子節(jié)點和復(fù)制節(jié)點 api:html
我是i子節(jié)點111
我是i子節(jié)點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);}替換方法需要兩個參數(shù),第一個新節(jié)點,第二個被替換子節(jié)點復(fù)制操作,復(fù)制得到相同節(jié)點,id具有唯一性,對id屬性重新復(fù)制判斷子節(jié)點是否存在方法 hasChildNodes? ? ? api:html
我是i子節(jié)點111
jswindow.onload=function(){? ? ? ? ? ? ? var a1=document.getElementById("a1");? ? ? ? var z1=document.getElementById("z1");? ? ? ? alert(a1.hasChildNodes());? ? ? ? alert(z1.hasChildNodes());}父節(jié)點調(diào)用,有子節(jié)點返回true,沒有false。無需參數(shù)總結(jié):基本節(jié)點處理,類型判斷(為1),屬性設(shè)置、獲取,類名獲取、設(shè)置,標(biāo)簽名獲取節(jié)點關(guān)系,父親,兄弟,孩子操作處理,創(chuàng)建,插入,替換,刪除,復(fù)制,有無子節(jié)點我們使用節(jié)點關(guān)系獲取子節(jié)點,下一個、上一個兄弟節(jié)點,最后子節(jié)點,發(fā)現(xiàn)發(fā)揮的節(jié)點,都是空格文本節(jié)點我們要做的就是對html元素的處理,就是node的類型為1,才是我們想要的也就是,獲取子節(jié)點,獲取的子節(jié)點都是元素標(biāo)簽兄弟節(jié)點也要是元素標(biāo)簽節(jié)點,這樣才能為我們所工作我們以這些節(jié)點操作為核心,用節(jié)點類型為1作為判斷依據(jù),返回一個數(shù)組(存放元素集合)為結(jié)果,做函數(shù)的封裝處理我們前面介紹了,獲取html元素和body接口,我們的頁面還會有一些很特殊的標(biāo)簽,需要在、提供特殊接口去處理,如:iframeiframe回載入一個html頁面作為子頁面,dom提供的接口獲取:ifrmaeele.contentDocument? 找到iframe,調(diào)用屬性得到子html頁面,htmljswindow.onload=function(){? ? ? var if1=document.getElementById("if1");? ? ? ? ? alert(if1.contentDocument.documentElement.offsetHeight); }會彈出內(nèi)部html的高度,這段代碼不要再谷歌測試,谷歌需要在服務(wù)器上運行才可以,要做http協(xié)議的