第五节 DOM节点树和时间定时器


DOM: Document Object Model(文档对象模型)

DOM树:


回流和重绘

重绘(repaint):

当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要 UI 层面的重新像素绘制,因此损耗较少。

常见的重绘操作有:

改变元素颜色

改变元素背景色

more ……

回流(reflow):

又叫重排(layout)。当元素的尺寸、结构或者触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。

常见的回流操作有

页面初次渲染

浏览器窗口大小改变

元素尺寸/位置/内容发生改变

元素字体大小变化

添加或者删除可见的 DOM 元素

……

重点:回流必定会触发重绘,重绘不一定会触发回流。重绘的开销较小,回流的代价较高。

DOM 操作


1、获取元素

1.1 根据id名获取

document.getElementById(idName)

1.2 根据标签名获取

document.getElementsByTagName(tagName)  // 返回一个集合 (类数组对象)  从整个文档获取

element.getElementsByTagName(tagName)    // 从element的后代元素中获取

1.3 根据类名获取(不兼容ie6~8)

document.getElementsByClassName(className)  // 返回一个集合(类数组对象)  从整个文档获取

element.getElementsByClassName(className)  // 从element的后代中获取

1.4 根据 name 属性值获取

正常的规范中,咱们只会给表单元素起name值,如果给其它元素设置name,在ie9以下版本浏览器不兼容,是获取不到的,

所以为了这种情况,咱们以后养成习惯,只给表单元素用name,非表单元素不用name

document.getElementsByName()  //返回集合  只有document才有该方法

1.5 根据选择器获取

注意:querySelector 和querySelectorAll 在ie6-ie8 下不兼容

document.querySelector(选择器)  //选择器第一个满足选择器条件的

document.querySelectorAll(选择器) //选择所有满足选择器条件的,返回nodeList(类数组对象)

element.querySelector(选择器)

element.querySelectorAll(选择器)

1.6 document.head 

      获取Head元素对象

1.7  document.body

    获取body元素对象

1.8 document.documentElement

   获取html元素对象

2、获取一屏幕的宽度或者高度,兼容所有的浏览器

// 获取一屏幕的高度

varvH=document.documentElement.clientHeight||document.body.clientHeight;

// 偶去一屏幕的宽度

varvW=document.documentElement.clientWidth||document.body.clientWidth;

3、id小妙招 直接把id当成变量去用的时候,可以获取相应的id元素。(浏览器的机制)

<script>

console.log(box1)

</script>

2、节点

●文档节点●属性节点●元素节点●文本节点●注释节点

2.1 文档节点

●nodeType(节点类型):9●nodeName(节点名称):"#document"●nodeValue(节点值):null

document.nodeType;

document.nodeName

document.nodeValue;

2.2 属性节点

●nodeType:2●nodeName:属性名●nodeValue:属性值getAttributeNode() 方法从当前元素中通过名称获取属性节点。

vara1=a1.getAttributeNode("href");// 获取属性节点

console.log(a1.nodeType);//2

console.log(a1.nodeName);//"href"; 属性名

console.log(a1.nodeValue);//"http://www.baidu.com"; 属性值

2.3 元素节点

●nodeType:1●nodeName:大写的标签名●nodeValue:null

<script>

console.log(box.nodeName)

</script>

2.4 文本节点

●nodeType:3●nodeName:"#text"●nodeValue:文本内容●在标准浏览器中,换行和空格也属于文本节点

varres=a1.childNodes[0];

console.log(res.nodeType);//3

console.log(res.nodeValue);//"百度";

console.log(res.nodeName);//"#text";

2.5 注释节点

●nodeType:8●nodeName:"#comment"●nodeValue:注释的内容

<!--a标签-->

百度

</a>

a1.childNodes;//NodeList(3) [text, comment, text]

a1.childNodes[1].nodeName;//"#comment"

a1.childNodes[1].nodeType;//8

a1.childNodes[1].nodeValue;//"a标签 "

3、节点之间关系的属性

节点类:

parentNode    父节点

childNodes    所有子节点的集合

firstChild    第一个子节点

lastChild    最后一个子节点

previousSibling  上一个兄弟节点

nextSibling      下一个兄弟节点

元素类:

children    所有子元素的集合

firstElementChild  第一个子元素  IE9+

lastElementChild    最后一个子元素 IE9+

previousElementSibling  上一个兄弟元素 IE9+

nextElementSibling    下一个兄弟元素  IE9+

3.1 parentNode获取当前节点唯一的父亲节点

<div>

<!--111-->

<div id="box">111</div>

</div>

</div>

<script>

console.log(box.parentNode)

</script>

3.2 childNodes获取当前节点所有的子节点

<!--我是注释-->

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

</ul>

<script>

console.log(main.childNodes);//NodeList(11) [text, comment, text, li, text, li, text, li, text, li, text]

3.3 firstChild获取被选节点的第一个子节点。

<!--我是注释-->

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

</ul>

<script>

console.log(main.firstChild);//#text

3.4 lastChild获取被选节点的最后一个子节点

<!--我是注释-->

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

</ul>

<script>

console.log(main.lastChild);//#text

3.5 previousSibling获取上一个哥哥节点

<!--我是注释-->

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

</ul>

<script>

console.log(main.previousSibling);//#text

3.6 nextSibling获取当前节点的下一个兄弟节点

<!--我是注释-->

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

</ul><!-- 1111 -->

<script>

console.log(main.nextSibling);//<!-- 1111 -->

3.7 children获取当前元素所有的元素子节点,但是在ie6--ie8下不兼容3.8 firstElementChild获取当前节点的第一个元素子节点 ie6-ie8 不兼容

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

</ul>

<script>

console.log(main.firstElementChild);

3.9 lastElementChild获取当前节点的最后一个元素子节点  ie6-ie8 不兼容

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!111</li>

</ul>

<script>

console.log(main.lastElementChild);

3.10 previousElementSibling获取上一个哥哥元素节点  ie6-ie8 不兼容<ul id="main">

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!111</li>

</ul>

<script>

console.log(main.previousElementSibling);

3.11 nextElementSibling获取当前节点的下一个兄弟元素节点    ie6-ie8 不兼容

<ul id="main">

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!111</li>

</ul>

<script>

console.log(main.nextElementSibling);

练习题

自己手动封装一个获取节点下面的所有子元素,要求考虑兼容性。

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport"content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible"content="ie=edge">

<title>Document</title>

<style>


</style>

</head>

<body>

<span id="span1">1</span>

<ul id="main">

<!--我是注释-->

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

</ul>

<span>2</span>

</body>

</html>

<script>

functionchildren(element){

varnodeLists=element.childNodes;

varresult=[]

for(vari=0;i<nodeLists.length;i++){

nodeLists[i].nodeType===1?result.push(nodeLists[i]):null;

}

returnresult;

}

console.log(children(main));

自己手动封装一个previousElementSibling,要兼容。

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport"content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible"content="ie=edge">

<title>Document</title>

<style>


</style>

</head>

<body>

<span id="span1">1</span>

<ul id="main">

<!--我是注释-->

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

<li>选择珠峰的,都是明智的!</li>

</ul>

<span id="span2">2</span>

</body>

</html>

<script>

functionpreviousElmentSibling(ele){

varpre=ele.previousSibling;

while(pre&&pre.nodeType!==1){

pre=pre.previousSibling;

}

returnpre;

}

console.log(previousElmentSibling(span2))

</script>

DOM 的增删改

1、createElement:创建一个元素

document.createElement("div");

2、createTextNode: 创建一个文本节点

var otext=document.createTextNode("哈哈!");

3、appendChild:把元素追加到一个容器的末尾

语法:[context].appendChild([元素]);

<div id="id1"></div>

  <script>

    var odiv = document.createElement("div");

    id1.appendChild(odiv);

    console.log(id1)

  </script>

4、insertBefore: 把一个元素插入到另一个元素的前面

首先要指定一个父节点

var  insertedNode = 父节点.insertBefore(要插入的节点, 插在这个节点之前)

var  insertedNode = parentNode.insertBefore(newNode, referenceNode)

newNode:将要插入的节点

referenceNode:被参照的节点(即要插在该节点之前)

insertedNode:插入后的节点

parentNode:父节点

<div id="id1">

  <p class="p1" id="p1">这是P1</p>

</div>

<script>

  var div = document.getElementById('id1');

  var p1 = document.getElementById('p1');

  var odiv = document.createElement("div");

  var returnDom = div.insertBefore(odiv, p1);

console.log(div)

</script>

5、cloneNode:把某一个节点进行克隆

【ele】.cloneNode();浅克隆: 只是克隆了一个节点,里面的内容还有样式都没克隆

【ele】.cloneNode(true);深克隆:把节点包含的所有内容进行克隆

<div id="id1">

    <p class="p1" id="p1">这是P1</p>

  </div>

  <script>

    var res = id1.cloneNode();

    var res2 = id1.cloneNode(true)

    console.log(res)

    console.log(res2)

  </script>

6、removeChild:移除某个节点

【context】.removeChild(ele);

<div id="id1">

    1111

    <p class="p1" id="p1">这是P1</p>

  </div>

  <script>

    id1.removeChild(p1);

    console.log(id1)

  </script>

7、set/get/removeAttribute

设置/获取/删除 当前元素的某一个自定义属性

setAttribute

getAttribute

removeAttribute

box.setAttribute("index", 1);

box.getAttribute("index");

box.removeAttribute("index");

console.log(box)

// 设置

// box["aa"] = 22;

// 获取

// box["aa"]

//移除

// delete box["aa"];

基于键值对方式 增删改:修改当前对象的堆内存空间完成的(在堆内存空间可以看到)

基于Attribute dom方法增删改,是修改html结构来完成的(此种方法设置的在结构上可以看到)

以上两种方式不能混用

题目

利用a标签的href来重新获取url参数

var str = "http://www.zhufengpeixun.cn?name=lili&age=18#123"

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Document</title>

</head>

<body>

  <script>

    var str = "http://www.zhufengpeixun.cn?name=lili&age=18#123"

    /*

    search: "?name=lili&age=18"

    hash: "#123"

    */

    function queryParams(str) {

      var a = document.createElement("a");

      a.href = str;

      var obj = {};

      console.log(a.search); //?name=lili&age=18

      console.log(a.hash); //#123

      //[name=lili,age=18]

      var search = a.search.substr(1);

      console.log(search);//name=lili&age=18

      obj.hash = a.hash ? a.hash : null;

      if (search) {

        var searchAry = search.split("&");

        console.log(searchAry)// ['name=lili', 'age=18']

        for (var i = 0; i < searchAry.length; i++) {

          var itemAry = searchAry[i];//name=lili  age=18

          var item = itemAry.split("=");

          console.log(item)//['name', 'lili']['age', '18']

          var key = item[0];

          var value = item[1];

          obj[key] = value;

        }

      }

      return obj;

    }

    var dd = queryParams(str);

    console.log(dd)

  </script>

</body>

</html>




1、时间对象

1.1【作用】:Date 对象用于处理日期和时间。

1.2【创建时间对象】: new Date()获取系统当前时间

var myDate=new Date(); //Tue Dec 24 2019 20:44:00 GMT+0800 (中国标准时间);

typeof myDate;====>"object"  // 获取到是一个对象,并不是字符串

1.3 时间对象相关属性和方法

●getFullYear();获取年●getMonth();获取月 0到11 代表1月到12月●getDate();获取日期●getDay();星期几 (0---6)代表周日到到周六●getHours();时●getMinutes();分●getSeconds();秒●getMilliseconds();毫秒●getTime();获取当前日期到1970年1月1号 00:00:00 之间的毫秒差●toLocaleString();// 获取到的是年月日,时分秒"2019/12/25 上午10:15:50"●toLocaleDateString();//  获取到是字符串的年月日,例如:"2019/12/25"●toLocaleTimeString();/ 获取到的是字符串的时分秒上午10:18:28

2、案例:钟表

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport"content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible"content="ie=edge">

<title>Document</title>

<style>

#clock{

height:50px;

line-height:50px;

text-align:center;

}

</head>

<body>

<div class="clock"id="clock">

</div>

<script>

functionclock(){

vartime=newDate;

varyear=time.getFullYear();

varmonth=time.getMonth()+1;//0-11 代表1月到12月

vardate=time.getDate();//日期

varday=time.getDay();//0-6代表周日到到六

varhours=time.getHours();

varminutes=time.getMinutes();

varseconds=time.getSeconds();

varweekStr=["日","一","二","三","四","五","六"];

varweek=weekStr[day];

varresult=year+"年"+month+"月"+date+"日"+"周"+week;

result+=hours+"时"+minutes+"分"+seconds+"秒";

returnresult;

}

vartime=clock();

document.getElementById("clock").innerHTML=time;

setInterval(function(){

vartime=clock();

document.getElementById("clock").innerHTML=time;

},1000)

</script>

</body>

</html>

补0操作:

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport"content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible"content="ie=edge">

<title>Document</title>

<style>

#clock{

height:50px;

line-height:50px;

text-align:center;

}

</head>

<body>

<div class="clock"id="clock">

</div>

<script>

varclock=document.getElementById("clock");

functiongetTime(){

vartime=newDate();

varyear=time.getFullYear();

varmonth=time.getMonth()+1;

vardate=time.getDate();

varday=time.getDay();

varhour=time.getHours();

varminutes=time.getMinutes();

varseconds=time.getSeconds();

varweek=["周日","周一","周二","周三","周四","周五","周六"];

varres=year+"年"+addZero(month)+"月"+addZero(date)+"日"+week[day]+" "+addZero(hour)+":"+addZero(minutes)+":"+addZero(seconds);

returnres;

}

functionaddZero(num){

returnnum<10?"0"+num:num;

}

varres=getTime();

clock.innerText=res;

setInterval(function(){

varres=getTime();

clock.innerText=res;

},1000)

</script>

</body>

</html>

3、定时器:

3.1、setTimeOut   

  一定的时间后,去执行某些事情,是单次调用

setTimeout(function(){

    alert("wasai!you are beautiful");

},1000)

3.2、setInterval

间隔多少时间后,去执行某些事情,是多次调用

setInterval(function(){

console.log("我真美!")

},1000)

3.3、定时器的参数说明

// 定时器可以传递多个参数:

// 1、执行的函数

// 2、时间

// 3、后面的参数就是执行函数在执行的时候传递的实参

setTimeout(function(num,s,m){

console.log(num,s,m);

},1000,2,3,6);

3.4、定时器是有返回值的,返回值代表定时器处于当前页面中的第几个

vartime1=setTimeout(function(){

console.log("wasai!you are beautiful");

},1000)

vartime2=setInterval(function(){

console.log("我真美!")

},1000)

vartime3=setTimeout(function(){

console.log("aa");

},1000)

console.log(time1)=====>1

console.log(time1)=====>2

console.log(time1)=====>3

3.5、定时器是异步任务,只要当咱们同步代码执行完毕之后,才能执行。

setTimeout(function(){

console.log("定时器");

},1000)

console.log("haha")

4、清除定时器的方法

●clearTimeout●clearInterval

5、练习

做一个抽奖程序,页面中有一个区域显示中奖人员的编号,在JS中写一段代码,要求每隔1秒中随机创建一个四位的数字(每一位数字的取值范围0-9),当10秒结束后,结束定时器,最后显示的四位数字即是中奖的号码

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>中奖</title>

    <style>

    #prize{

        width:200px;

        height:50px;

        border:1px solid green;

    }

    </style>

</head>

<body>

    <div class="prize" id="prize"></div>

</body>

</html>

<script>

    function getCode(){

        var str="0123456789";

        var result="";

        for(var i=0;i<4;i++){

            var index=Math.floor(Math.random()*9);

            result+=str[index];

        }

      prize.innerHTML=result;

      return result;

    }

    var time1=setInterval(function(){

        getCode();

    },1000);

    setTimeout(function(){

        clearInterval(time1);

    },10000)



</script>

倒计时案例:

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport"content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible"content="ie=edge">

<title>Document</title>

<style>

*{

margin:0;

padding:0;

}

body {

background:darkslateblue;

}

#time{

height:100px;

line-height:100px;

border:1px dashed yellow;

text-align:center;

color:#fff;

font-size:26px;

}

</head>

<body>

<div id="time">

</div>

<script>

/*

      倒计时:

      目标时间:2021年12月14号

      目标时间-现在的时候=还剩多少时间?

      为了方便计算时间差,我们统一转成到1970年...的时间戳

    */

functioncountDown(targetStr){

// 目标时间

vartargetTime=newDate(targetStr);

// 现在的时间

varnowTime=newDate()

// 时间差,得出来的是毫秒

vardiffTime=targetTime-nowTime;

// 把时间差换算成时、分、秒

varhours=Math.floor(diffTime/(1000*60*60));

varminutes=Math.floor((diffTime-hours*1000*60*60)/(1000*60));

varseconds=Math.floor((diffTime-hours*1000*60*60-minutes*60*1000)/1000);

varresult=formatter(hours)+"时"+formatter(minutes)+"分"+formatter(seconds)+"秒";

returnresult;

}

functionformatter(val){

returnval=Number(val)<10?"0"+val:val;

}

varres=countDown("2021-12-24 00:00:00");

time.innerHTML=res;

console.log(res)

setInterval(()=>{

varres=countDown("2021-12-24 00:00:00");

time.innerHTML=res;

},1000);

</body>

</html>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容