10-JavaScript的DOM对象

10-DOM


1.DOM简介

DOM,全称Document Object Model文档对象模型。
1).JS中通过DOM来对HTML文档进行操作。只要理解了DOM就可以随心所欲的操作WEB页面。
-文档——文档表示的就是整个的HTML网页文档
-对象——对象表示将网页中的每一个部分都转换为了一个对象。
-模型——使用模型来表示对象之间的关系,这样方便我们获取对象。
2).要使用DOM来操作网页,我们需要浏览器至少得先给我一个对象才能去完成各种操作
所以浏览器已经为我们提供了一个document对象,它是一个全局变量可以直接使用document代表的是整个的网页
3).浏览器已经为我们提供文档节点对象这个对象是window属性,可以在页面中直接使用,文档节点代表的是整个网页

<button id="btn">我是一个按钮 </button>
<script type="text/javascript">
     //获取到button对象
     var btn = document.getElementById("btn");
     //修改按钮的文字
     btn.innerHTML="I'm Button";
</script>

2.节点

1).节点:

-Node——构成HTML文档最基本的单元。
-常用节点分为四类:
​ -文档节点:整个HTML文档
​ -元素节点:HTML文档中的HTML标签
​ -属性节点︰元素的属性
​ -文本节点:HTML标签中的文本内容

2). document对象

- document对象表示的是整个网页
- document对象的原型链
	HTMLDocument -> Document -> Node -> EventTarget -> 0bject.prototype -> null
-凡是在原型链上存在的对象的属性和方法都可以通过Document去调用I
-部分属性:
    document.documentElement --> html根元素
    document.head --> head元素
    document.title --> title元素
    document.body --> body元素
    document.links -->获取页面中所有的超链接
    ...
console.log(document.links);

3).获取元素节点

元素节点对象(element):

-在网页中,每一个标签都是一个元素节点
-如何获取元素节点对象?
    1.通过document对象来获取元素节点
    2.通过document对象来创建元素节点
-通过document来获取已有的元素节点:
    document.getElementById()
-documentElement保存的是html根标签
	document.documentElement;
	输出是html标签中的内容
-在document中有一个属性body,它保存的是body的引用
	输出是body标签中的内容
–根据id获取一个元素节点对象
    document.getElementsByClassName( )
        -根据元素的class属性值获取一组元素节点对象
        -返回的是一个类数组对象
        -该方法返回的结果是一个实时更新的集合
        	当网页中新添加元素时,集合也会实时的刷新
        -但是该方法不支持IE8及以下的浏览器
    document.getElementsByTagName( )
        -根据标签名获取一组元素节点对象-返回的结果是可以实时更新的集合
        - document.getElementsByTagName("*")获取页面中所有的元素
    document.getElementsByName( )
        -根据name属性获取一组元素节点对象-返回一个实时更新的集合
        -主要用于表单项
    document.querySelectorAll()
        -根据选择器去页面中查询元素
        -会返回一个类数组(不会实时更新)
        -会将符合条件的元素封装到一个数组中返回,即使符合条件的元素只有一个,它也会返回数组
    document.querySelector()
        -根据选择器去页面中查询第一个符合条件的元素
        -需要一个选择器的字符串作为参数,可以根据一个CSS选择器来查询一个元素节点对象
        -IE8中没有getElementsByClassName()但是可以使用querySelector()代替
        -使用该方法总会返回唯一的一个元素,如果满足条件的元素有多个,那么它只会返回第一个,没有就返回null
-创建一个元素节点
    document.createElement( )
        -根据标签名创建一个元素节点对象
        -它需要一个标签名作为参数,将会根据该标签名创建元素节点对象,并将创建好的对象作为返回值返回
<button id="btn">点我一下</button>
<!-- span.s1*5 -->
<span class="s1"></span>
<span class="s1"></span>
<span class="s1"></span>
<span class="s1"></span>
<span class="s1"></span>
<script>
    const span=document.getElementsByClassName("s1")
    console.log(span);
    for (let i = 0; i < span.length; i++) {
        console.log(span[i]);
        span[i].innerText="哈哈哈"+i
    }
    const span2=document.querySelectorAll("span")
</script>

4).元素的属性和方法

div元素的原型链:
	HTMLDivElement ->HTMLElement -> Element -> Node -> ...
通过元素节点对象获取其他节点的方法:
    element.childNodes			    获取当前元素的子节点,包括文本节点在的所有节点,DOM标签间空白也会当成文本节点
                                        注意:在IE8及以下的浏览器中,不会将空白文本当成子节点
    element.children				获取当前元素的子元素
    element.firstChild				可以获取到当前元素的第一个子节点(包括空白文本节点)
    element.firstElementChild		 获取当前元素的第一个子元素
    									不支持IE8及以下的浏览器,如果需要兼容他们尽量不要使用			
    element.lastElementChild		 获取当前元素的最后一个子元素
    element.nextElementSibling		 获取当前元素的下一个兄弟元素
   	element.nextSibling;
    element.previousElementSibling	 获取当前元素的前一个兄弟元素,IE8以下不支持
   	element.previousSibling				也可能获取到前面的空白文本
    element.parentNode				获取当前元素的父节点
    element.tagName					获取当前元素的标签名
<div id="box1">
    我是div
    <span class="s1">我是s1</span>
    <span class="s1">我是s1</span>
</div>
<span class="s1">我是s1</span>
<script>
    const div=document.getElementById("box1")
    console.log(div);
</script>

5).文本节点

在DOM中,网页中所有的文本内容都是文本节点对象,可以通过元素来获取其中的文本节点对象,但是通常不会这么做

我们可以直接通过元素去修改其中的文本
修改文本的三个属性:
    element.textContent获取或修改元素中的文本内容
    	-获取的是标签中的内容,不会考虑css样式
    element.innerText获取或修改元素中的文本内容
        -innerText获取内容时,会考虑css样式
        –通过innerText去读取CSS样式,会触发网页的重排(计算CSS样式)
        -当字符串中有标签时,会自动对标签进行转义
    		- <li> --> &lt;li&gt;
    element.innerHTML获取或修改元素中的html代码
        -可以直接向元素中添加html代码
        -innerHTML插入内容时,有被xss注入的风险
        -innerHTML用于获取元素内部的HTML代码的对于自结束标签,这个属性没有意义
<div id="box1">
    <span style="display:none;">我是div</span>
    <span style="text-transform: uppercase;">我是div</span>
</div>
<script>
    const box1=document.getElementById("box1")
    console.log(box1.textContent);
    box1.textContent="新的内容"
    </div>
</script>

6).属性节点(Attr)

a.在DOM也是一个对象,通常不需要获取对象而是直接通过元素即可完成对其的各种操作
b.如何操作属性节点:

①.方式一:

读取:元素.属性名(注意,class属性需要使用className来读取)
		读取一个布尔值时,会返回true或false
修改:元素.属性名=属性值

②.方式二:

读取:元素.getAttribute(属性名)
修改:元素.setAttribute(属性名,属性值)
删除:元素.removeAttribute(属性名)
<inrput disabled="disabled" type="text" name="username" value="admin">
    <script>
        const input=document.querySelector("[name=username]")
        console.log(input.type);
        console.log(input.getAttribute("name "));
        input.setAttribute("value","孙悟空")
        input.removeAttribute("disabled","disabled")
    </script>


3.事件

<!-- 
  我们可以在事件对应的属性中设置一些js代码,
      这样当事件被触发时,这些代码将会执行
      这种写法我们称为结构和行为耦合,不方便维护,不推荐使用
-->
<button id="btn" onmousedown="alert('我被点了')">点我一下</button>

1).事件(event)

a.事件就是用户和页面之间发生的交互行为。比如:点击按钮、鼠标移动、双击按钮、敲击键盘、松开按键…
b.可以通过为事件绑定响应函数(回调函数)),来完成和用户之间的交互
c.绑定响应函数的方式:
①.可以直接在元素的属性中设置
②.可以通过为元素的指定属性设置回调函数的形式来绑定事件
-使用对象.事件=函数的形式绑定响应函数(一个事件只能绑定一个响应函数 后面定义的方法会覆盖前面的方法)
③.可以通过元素addEventListener()方法来绑定事件
-通过这个方法也可以为元素绑定响应函数
-参数:
Ⅰ.事件的字符串,不要on
Ⅱ.回调函数,当事件触发时该函数会被调用
Ⅲ.是否在捕获阶段触发事件,需要一个布尔值,一般都传false
-使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,
-这样当事件被触发时,响应函数将会按照函数的绑定顺序执行
-这个方法不支持IE8以下的浏览器(兼容性问题)

<burtton id="btn">点我一下</button>
<script>
//获取按钮对象
const btn = document.getElementById("btn")
//可以为按钮的对应事件属性绑定处理函数的形式来响应事件
//绑定一个单击事件
//像这种为单击事件绑定的函数,我们称为单击响应函数 
/* btn.onclick = function () {
      alert('我又被点儿')
  } */
/* btn.onclick = function () {
      alert('我又被点了')
  } */

btn.addEventListener('click', function () {
  alert('嘻嘻嘻')
})
btn.addEventListener('click', function () {
  alert('哈哈哈')
})
</script>
a.兼容性问题
attachEvent( )

​ a.在IE8中可以使用attachEvent()来绑定事件
​ b.参数:
​ ①.事件的字符串,要on
​ ②.回调函数
​ c.这个方法也可以同时为一个事件绑定多个处理函数,不同的是它是后绑定先执行,执行顺序和addEventListener()相反

btn.attachEvent("onclick",function(){
alert(1);
}); 
/* 兼容性问题 */
//定义一个函数,用来为制定元素绑定响应函数
/* 
      addEventListener()中的this是绑定事件的对象
      attachEvent()中的this,是window
          需要统一两个方法的this
  */
/* 
      参数:
      obj 要绑定事件的对象
      eventstr    事件的字符串(不要on)
      callback    回调函数
  */
function bind(obj, eventStr, callback) {
if (obj.addEventListener) {
  //大部分浏览器兼容的方法
  obj.addEventListener(eventStr, callback, false);
} else {
  /* 
              this是谁由谁调用决定
               callback.call(obj);
          */
  //IE8以下
  obj.attachEvent("on" + eventStr, function () {
      //在匿名函数中调用回调函数
      callback.call(obj);
  });
}
}
bind(btn, "click", function () {
alert(1);
});
a.滚轮事件
<style>
#box1{
  width: 300px;
  height: 300px;
  background-color: yellowgreen;
}
</style>
<div id="box1"></div>
<script>   
//获取id为box1的div
var box1=document.getElementById("box1");
//为box1绑定一个鼠标滚轮滚动的事件,会在滚轮滚动时触发
box1.onmousewheel=function(event){
          event=event||window.event;
}
</script>
onmousewheel

-鼠标滚轮滚动的事件,会在滚轮滚动时触发,但是火狐不支持该属性
-在火狐中需要使用DOMMousescroll来绑定滚动事件,注意该事件需要通过addEventListener()函数来绑定

//为火狐绑定滚轮事件
bind(box1,"DOMMousescroll",box1.onmousewheel);
function bind(obj,eventStr,callback){
if(obj.addEventListener){
  //大部分浏览器兼容的方法
  obj.addEventListener(eventStr,callback,false);
}else{
/* 
      this是谁由谁调用决定
      callback.call(obj);
*/
  //IE8以下
  obj.attachEvent("on"+ eventStr,function(){
      //在匿名函数中调用回调函数
      callback.call(obj);
  });
}
}
bind(box1,"DOMMousescroll",function(){
alert("滚了");
}); 

判断鼠标滚轮的方向

event.wheelDelta

-可以获取鼠标滚轮滚动的方向
向下滚-120
向上滚120
-wheelDelta这个值不看大小,只看正负

alert(event.wheelDelta);

wheelDelta这个属性火狐中不支持

在火狐中使用event.detail来获取滚轮滚动的方向
向上滚 -3
向下滚 3

alert(event.detail);
//当鼠标滚轮向下滚动时,box1变长,当滚轮向上滚动时,box1变短
if(event.wheelDelta>0 || event.detail<0){
//向下滚动时,box1变短
box1.style.height=box1.clientHeight-10+"px";
}else{
//向下滚动时,box1变长
box1.style.height=box1.clientHeight+10+"px";
}

用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false
需要使用event来取消默认行为event.preventDefault();
但是IE8不支持event.preventDefault();,如果直接调用会报错

event.preventDefault && event.preventDefault();
/* 
  当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,
  这是浏览器的默认行为,如果不希望发生,则可以取消默认行为
  return false;
*/
b.键盘事件
onkeydown

​ -按键被按下
​ -对于onkeydown来说如果一直按着某个按键不松手,则事件会一直触发
​ -当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常的快
​ 这种设计是为了防止误操作的发生。|

onkeyup

​ -按键被松开

键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document

document.onkeydown=function(event){
event=event||window.event;
/* 
  可以通过keyCode来获取按键的编码
  可以判断哪个按键被按下
  除了keycode,事件对象中还提供了几个属性
      altKey
      ctrlKey
      shiftKey
      -这个三个用来判断alt ctrl 和shift是否被按下
      	如果按下则返回true,否则返回false
*/
if(event.keyCode===89 && event.ctrlKey){
  alert("y和ctrl被按下");
}
console.log(event.keyCode);
console.log(event.key); 
}
//获取input
var input=document.getElementsByTagName("input")[0];
input.onkeydown=function(event){
event=event||window.event;
//数字是48-57
//使文本框不能输入数字
console.log(event.keyCode);
if(event.keyCode>=97 && event.keyCode<=105){
  return false; 
}
//console.log("按键被按下");
//在文本框中输入内容,属于onkeydown的默认行为
//如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中
return false;  
}

2).文档的加载

网页是自上向下加载的,如果将js代码编写到网页的上边,
JS代码在执行时,网页还没有加载完毕,这时会出现无法获取到DOM对象的情况

​ window.onload 事件会在窗口中的内容加载完毕之后才触发
​ document的DOMContentLoaded事件会在当前文档加载完毕之后触发

如何解决这个问题:

​ 1.将script标签编写到body的最后(*****)
​ 2.将代码编写到window.onload的回调函数中

window.onload = function () {
var btn = document.getElementById("btn");
btn.onclick = function () {
  alert("hello");
}
} 
window.addEventListener("load",function(){
var btn = document.getElementById("btn");
btn.onclick = function () {
  alert("hello");
}
}) 

​ 3.将代码编写到document对象的DOMContentLoaded的回调函数中(执行时机更早)

document.addEventListener("DOMContentLoaded",function(){
var btn = document.getElementById("btn");
btn.onclick = function () {
  alert("hello");
}
})

​ 4.将代码编写到外部的js文件中,然后以defer的形式进行引入(执行时机更早,早于DOMContentLoaded)(*****)

<script defer src="/JS/script.js"></script>
注意:

for循环会在页面加载完成之后立即执行,而响应函数会在超链接被点击时才执行当响应函数执行时,for循环早已执行完毕


4.元素的修改

<button id="btn1">点我一下1</button>
<button id="btn2">点我一下2</button>
<hr>
<ul id="list">
 <li id="swk">孙悟空</li>
 <li>猪八戒</li>
 <li>沙悟净</li>
 </url>
<script>
 const btn1=document.getElementById("btn1")
 const btn2=document.getElementById("btn2")
 const list=document.getElementById("list")
 btn1.addEventListener('click',function(){
     const name="omg"
     const li=document.createElement("li")
     li.textContent="唐僧"
     li.id="ts"
 })
 btn2.addEventListener('click',function(){
     const li=document.createElement("li")
     li.textContent="蜘蛛精"
     li.id="zzj"
     //获取swk
     const swk=document.getElementById("swk")
     //remove()用来删除当前元素
     swk.remove()
 })
</script>
①.appendChild()

​ 用于给一个节点添加子节点

list.appendChild(li)

②.insertAdjacentElement()

​ -可以向元素的任何位置添加元素
​ -两个参数:1.要添加的位置2.要添加的元素
​ beforeend 标签的最后
​ afterbegin 标签的开始
​ beforebegin 在元素的前边插入元素(兄弟元素)
​ afterend 在元素的后边插入元素(兄弟元素)

list.insertAdjacentElement("beforebegin",li)

list.insertAdjacentHTML("beforeend","<li id="+name+">白骨精</li>")

insertBefore()

​ -可以在指定的子节点前插入新的子节点

语法:		
		父节点.insertBefore(新节点,旧节点);
③.replaceWith()

​ 使用一个元素替换当前元素

swk.replaceWith(li)

replaceChild()

​ -可以使用指定的子节点替换已有的子节点

语法:
	父节点.replaceChild(新节点,旧节点);
④.remove()

​ 用来删除当前元素

swk.remove()

removeChild()

​ -可以删除一个子节点

语法:
 父节点.removeChild(子节点);
 子节点.parentNode.removeChild(子节点);

5.节点的复制

-使用cloneNode() 方法对节点进行复制时,它会复制节点的所有特点包括各种属性
-这个方法默认只会复制当前节点,而不会复制节点的子节点
-可以传递一个true作为参数, 这样该方法也会将元素的子节点一起复制

<button id="btn01">点我一下</button>
<ul id="list1">
 <li id="l1">孙悟空</li>
 <li id="l2">猪八戒</li>
 <li id="l3">沙和尚</li>
</ul>
<ul id="list2">
 <li>蜘蛛精</li>
</ul>
<script>
 const list2=document.getElementById("list2")
 const l1=document.getElementById("l1")
 const btn01=document.getElementById("btn01")
 btn01.onclick=function(){
     // const newl1=l1.cloneNode()//用来对节点进行复制
     const newl1=l1.cloneNode(true)
     newl1.id="newl1"
     list2.appendChild(newl1)
 }
</script>


6.操作CSS样式

1).修改CSS样式

通过JS修改元素的样式:

​ 通过style属性设置和读取的都是内联样式,无法读取样式表中的样式

语法:
	元素.style.样式名=样式值
注意:
 如果CSS的样式名中含有-,这种名称在JS中是不合法的比如background-color
 需要将这种样式名修改为驼峰命名法,去掉-,然后将-后的字母大写

我们通过style属性设置的样式都是内联桂式,而内联样式有较高的优先级,所以通过JS修改的样式往往会立即显示
但是如果在样式中写了!important,则此时样式会有最高的优先级,
即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效,所以尽量不要为样式添加 !importantl

<style type="text/css">
 #box1{
     width: 200px;
     height: 200px;
     background-color: red;
 }
</style>

<div id="box1"></div>
<button id="btn1">点我一下</button>

<script>
 //获取box1
 var box1=document.getElementById("box1");
 //为按钮绑定单击响应事件
 var btn1=document.getElementById("btn1");
 btn1.onclick=function(){
     box1.style.backgroundColor="yellow";
 }
</script>

2).读取CSS样式

<style type="text/css">
 #box1{
     width: 200px;
     height: 200px;
     background-color: red;
 }
 #box1::before{
     color: black;
 }
</style>

<div id="box1"></div>
<button id="btn1">点我一下</button>

<script>
 //点击按钮以后读取box1的样式
 //获取box1
 var box1=document.getElementById("box1");
 //为按钮绑定单击响应事件
 var btn1=document.getElementById("btn1");
 btn1.onclick=function(){

 }
</script>

获取元素的当前显示的样式:

语法:
	元素.currentStyle.样式名
		它可以用来读取当前元素正在显示的样式
		如果当前元素没有设置该样式,则获取它的默认值
		currentstyle只有IE浏览器支持,其他的浏览器都不支持
alert(box1.currentStyle.width);		//200
在其他浏览器中可以使用
 getComputedstyle()
 	-这个方法来获取元素当前的样式
 	-会返回一个一个对象,这个对象中包含了当前元素所有的生效的样式
 	-这个方法是window的方法,可以直接使用
 	-需要两个参数
         第一个:要获取样式的对象
         第二个:可以传递一个伪元素,一般都传null
 	-该方法会返回一个对象,对象中封装了当前元素对应的样式
 		可以通过对象.样式名来读取样式
 		如果获取的样式没有设置,则会获取到真实的值,而不是默认值
 			样式对象中返回的样式值,不一定能来拿来直接计算
 			所以使用时,一定要确保值是可以计算的才去计算
 			比如:没有设置width,它不会获取到auto,而是一个长度
 	-但是该方法不支持IE8及其以下的浏览器  
alert((getComputedStyle(box1,null)).width); 
alert((getComputedStyle(box1,"::before")).color); 
alert(getStyle(box1,"width"));	//200

通过currentStyle和getComputedStyle()读取到的样式都是只读的,不能修改,如果要修改必须通过style属性


定义一个函数,用来获取指定元素的当前的样式:

参数:
obj 要获取样式的元素
name 要获取的样式名

function getStyle(obj,name){
 if(window.getComputedStyle){
     //正常浏览器,具有getComputedStyle()方法
     return getComputedStyle(obj,null)[name];
 }else{
     //IE8的方式,没有getComputedStyle()方法
     return ob.currentStyle[name];
 }
}

3).通过属性读取样式

<style>
 #box1{
     width: 200px;
     height: 200px;
     background-color: red;
     padding: 10px;
     border: 10px solid yellow;
 }
 #box2{
     background-color: #bfa;
     padding: 100px;
 }
 #box4{
     width: 200px;
     height: 300px;
     background-color: #bfa;
     overflow: auto;
 }
 #box5{
     width: 600px;
     height: 600px;
     background-color: yellow;
 }
</style>

<button id="btn1">点我一下</button>
<div id="box4">
 <div id="box5"></div>
</div>
<br><br>
<div id="box3" style="position:relative;">
 <div id="box2" style="position:relative;">
     <div id="box1"></div>
 </div>
</div>

<script>
 var box1=document.getElementById("box1");
 var btn1=document.getElementById("btn1");
 btn1.onclick=function(){

 }
</script>
①.clientwidth 和 clientHeight

​ -这两个属性可以获取元素的可见宽度和高度
​ 获取元素内部的宽度和高度(包括内容区和内边距)
​ -这些属性都是不带px的,返回都是一个数字,可以直接进行计算
​ -会获取元素宽度和高度,包括内容区和内边距
​ -这些属性都是只读的,不能修改

alert(box1.clientWidth);		//220
②.offsetwidth 和 offsetHeight

​ -获取元素的整个的宽度和高度,包括内容区、内边距和边框

alert(box1.offsetWidth);		//220
③.offsetParent

​ -可以用来获取当前元素的定位父元素
​ -会获取到离当前元素最近的开启了定位的祖先元素
​ 如果所有的祖先元素都没有开启定位,则返回body

alert(box1.offsetParent.id);		//box2
④.offsetLeft 和 offsetTop

offsetLeft
-当前元素相对于其定位父元素的水平偏移量
offsetTop
-当前元素相对于其定位父元素的垂直偏移量

alert(box1.offsetLeft);			//100
⑤.scrollHeight 和 scrollWidth

元素. scrollHeight
元素. scrollWidth
-获取元素滚动区域的大小

var box4=document.getElementById("box4");
alert(box4.clientHeight);		//283
alert(box4.scrollHeight);		//600
⑥.scrollLeft 和 scrollTop

scrollLeft
-可以获取水平滚动条滚动的距离
scrollTop
-可以获取垂直滚动条滚动的距离

alert(box4.scrollLeft);
alert(box4.scrollTop);
⑦.相等关系

当满足scrollHeight - scrollTop == clientHeight
说明垂直滚动条滚动到底了
当满足scrollwidth - scrollLeft == clientwidth
说明水平滚动条滚动到底

alert(box4.clientHeight);		//283
alert(box4.scrollHeight-box4.scrollTop);		//600

4).操作Class修改样式

<style>
 .box1{
     width: 400px;
     height: 400px;
     background-color: tomato;
 }
 .box2{
     background-color: yellow;
 }
</style>

<button id="btn01">点击</button>
 <hr>
 <div class="box1"></div>

<script>
	const btn01=document.getElementById("btn01")
     const box1=document.querySelector(".box1")
     btn01.onclick=function(){

     }
</script>

除了直接修改样式外,也可以通过修改class属性来间接的修改样式
-通过class修改样式的好处:
①.可以一次性修改多个样式
②.对JS和CSS进行解耦

box1.className += " box2"

元素.classList是一个对象,对象中提供了对当前元素的类的各种操作方法
 元素.classList.add()			向元素中添加一个或多个class
 元素.classList. remove()		移除元素中的一个或多个class
 元素.classList. toggle()		切换元素中的class
 元素.classList.replace()		替换class
 元素.classList. contains()	检查lclass
box1.classList.add("box2")
console.log(box1.classList.contains("box2"));

7.事件对象

<style>
      #areaDiv{
         border: 2px solid black;
         width: 400px;
         height: 100px;
      }
      #showMsg{
         border: 2px solid black;
         width: 400px;
         height: 50px;
      }
 </style>

<div id="box1"></div>
 <div id="areaDiv"></div>
 <br>
 <div id="showMsg"></div>

event事件——事件对象
-事件对象是有浏览器在事件触发时所创建的对象,这个对象中封装了事件相关的各种信息
-通过事件对象可以获取到事件的详细信息,比如:鼠标的坐标、键盘的按键…
-浏览器在创建事件对象后,会将事件对象作为响应函数的参数传递,所以我们可以在事件的回调函数中定义一个形参来接收事件对象
-当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,
在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标键盘哪个按键被按下鼠标滚轮滚动的方向…

//获取两个div
var areaDiv=document.getElementById("areaDiv");
var showMsg=document.getElementById("showMsg");
areaDiv.onmousemove=function(event){
/* 
 在IE8中,响应函数被触发时,浏览器不会传递事件对象,
 在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的
*/
 //解决事件对象的兼容性问题
 /* if(!event){
     	event=window.event;
     } */
 event=event||window.event;
/* 
 clientX可以获取鼠标指针的水平坐标
 cilentY可以获取鼠标指针的垂直坐标
*/
 var x=event.clientX;
 var y=event.clientY;
 //alert("我动了");
 //在showMsg中显示鼠标的坐标
 showMsg.innerHTML="x="+x+"y="+y;
}
}


8.Event对象

<style>
 #box1{
     width: 300px;
     height: 300px;
     background-color: #bfa;
 }
 #box2{
     width: 200px;
     height: 200px;
     background-color: yellowgreen;
 }
 #box3{
     width: 100px;
     height: 100px;
     background-color: tomato;
 }
</style>

<div id="box1">
 <div id="box2">
     <div id="box3"></div>
 </div>
</div>
<a id="chao" href="https://baidu.com">超链接</a>

在DOM中存在着多种不同类型的事件对象

-多种事件对象有一个共同的祖先 Event
    - event.targetl					触发事件的对象
    - event.currentTarget			绑定事件的对象(同this)
    - event.stopPropagation()		停止事件的传导
    - event.preventDefault( )		取消默认行为
    -event.cancelBubble			    将事件对象cancelBubble设置为true,即可取消冒泡
const box1=document.getElementById("box1")
const box2=document.getElementById("box2")
const box3=document.getElementById("box3")
const chao=document.getElementById("chao")
chao.addEventListener("click",(event)=>{
    event.preventDefault()  //取消默认行为
    alert("被点了");
    /* return false; */	
})

在事件的响应函数中:
event.target表示的是触发事件的对象(触发事件的对象不一定是box1,box2和box3一样可以触发)
this 表示绑定事件的对象

box1.addEventListener("click",function(event){
    console.log(event.target);
    console.log(this );
    console.log("Hello 我是box1");
})
box2.addEventListener("click",function(event){
    alert("我是box2")
})
box3.addEventListener("click",function(event){
    event.stopPropagation()//取消事件的冒泡传递
    alert("你好 我是box3")
})

点击box1:

点击box2:

点击box3:


9.事件的发生

1).事件的冒泡(bubble)

-事件的冒泡就是指事件的向上传到
-当元素上的某个事件被触发后,其祖先元素上的相同事件也会同时被触发
-冒泡的存在大大的简化了代码的编写,但是在一些场景下我们并不希望冒泡存在,不希望事件冒泡时,可以通过事件对象来取消冒泡

<div id="circle"></div>
<div id="box1"></div>
<!-- 事件的冒泡和元素的样式无关,之和结构相关 -->
<div id="box2" onclick="alert(2)">
<div id="box3" onclick="alert(3)"></div>
</div>

<script>
/* 使小绿球跟随鼠标移动 */
const circle=document.getElementById("circle")
const box1=document.getElementById("box1")
//事件需要绑定给document,绑定给小绿球太小了
document.addEventListener("mousemove",(event)=>{
  circle.style.left=event.x+"px"
  circle.style.top=event.y+"px"
})
box1.addEventListener("mousemove",(event)=>{
  event.stopPropagation()		//取消事件的传导
})
</script>

2).事件的委派

-指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素
​ 从而通过祖先元素的响应函数来处理事件。
-事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
-委派就是将本该绑定给多个元素的事件,统一绑定给document,这样可以降低代码复杂度方便维护

<button id="btn">点击</button>
<hr>
<ul id="list">
<li><a href="javasctript:;">超链接一</a></li>
<li><a href="javasctript:;">超链接二</a></li>
<li><a href="javasctript:;">超链接三</a></li>
<li><a href="javasctript:;">超链接四</a></li>
</ul>
<script>
var u1=document.getElementById("u1");
//点击按钮后添加超链接
var btn01=document.getElementById("btn01");
btn01.onclick=function(){
  //创建一个li
  var li=document.createElement("li");
  li.innerHTML="<a href='#' class='link'>超链接一</a>";
  u1.appendChild(li);
}
/*

      */
//获取所有的a
var allA=document.getElementsByTagName("a");
//遍历
/*  for(var i=0;i<allA.length;i++){
          allA[i].οnclick=function(){

          };
      } */
</script>

为每一个超链接都绑定一个单击响应函数,这里我们为每一个超链接都绑定了一个单击响应函数,
这种操作比较麻烦,而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定

新建一个子元素超链接便遍历一遍元素数组的话会影响程序的性能

思路:
可以将事件统一绑定给document,这样点击超链接时由于事件的冒泡,
会导致document上的点击事件被触发,这样只绑定一次,所有的超链接都会具有这些事件

const links=document.getElementsByTagName("a")
const list=document.getElementById("list")
const btn=document.getElementById("btn")
//只绑定一次事件,既可以让所有的超链接,包括当前的和未来新建的超链接都具有这些事件
document.addEventListener("click",(event)=>{
//console.log(Array.from(links));
if ([...links].includes(event.target)) {
  alert(event.target.textContent)
}
})
//点击按钮后,在UI中添加一个新的li
btn.addEventListener("click",()=>{
list.insertAdjacentHTML("beforeend","<li><a href='javasctript:;'>新的超链接</a></li>")
})

3).事件的捕获

a.事件的捕获,指事件从外向内的传导,当前元素触发事件以后,会先从当前元素最大的祖先元素开始向当前元素进行事件的捕获
b.关于事件的传播网景公司和微软公司有不同的理解:
①.微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,
然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
②.网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,
然后在向内传播给后代元素
c.W3C综合了两个公司的方案,将事件传播分成了三个阶段
①.捕获阶段——在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
②.目标阶段——事件捕获到目标元素,捕获结束开始在目标元素上触发事件
③.冒泡阶段——事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件

d.如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true,
一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
e.IE8及以下的浏览器中没有捕获阶段

<div id="box1">
    <div id="box2">
        <div id="box3"></div>
    </div>
</div>

<script>
    const box1=document.getElementById("box1")
    const box2=document.getElementById("box2")
    const box3=document.getElementById("box3")
    box1.addEventListener("click",(event)=>{
        //alert(1)
        alert("1"+event.eventPhase) 
        //eventPhase 表示事件触发的阶段
        //返回的是一个数值:1捕获阶段 2目标阶段 3冒泡阶段
    })
    box2.addEventListener("click",(event)=>{
        //alert(2)
        alert("2"+event.eventPhase)
    })
    box3.addEventListener("click",(event)=>{
        //alert(3)
        alert("3"+event.eventPhase)
    })
</script>

10.项目练习

1).练习一:

学生信息添加

<div class="info">
 <h1>学生信息添加</h1>
 <div class="up">
     <!-- autocomplete="off"取消文本框提示已输入过得文字 -->
     <!-- placeholder=""设置文本框中灰色的提示文字 -->
     <label for="姓名">
         姓名:
         <input type="text" value="" id="name" placeholder="请输入名字" autocomplete="off" />
     </label>
     <label for="">
         性别:
         <input type="text" value="" id="sex" placeholder="请输入性别" autocomplete="off" />
     </label>
     <label for="">
         年龄:
         <input type="number" value="" id="age" placeholder="请输入年龄" autocomplete="off" />
     </label>
     <label for="">
         邮箱:
         <input type="email" value="" id="email" placeholder="请输入邮箱" autocomplete="off" />
     </label>
     <input type="button" value="添加" id="add" />
 </div>
 <table>
     <thead>
         <tr>
             <th>姓名</th>
             <th>性别</th>
             <th>年龄</th>
             <th>邮箱</th>
             <th>操作</th>
         </tr>
     </thead>
     <tbody id="tbody">
         <tr>
             <td>孙悟空</td>
             <td></td>
             <td>26</td>
             <td>swk@qq.com</td>
             <td><a href="#">删除</a></td>
         </tr>
         <tr>
             <td>猪八戒</td>
             <td></td>
             <td>28</td>
             <td>zbj@qq.com</td>
             <td><a href="#">删除</a></td>
         </tr>
         <tr>
             <td>沙悟净</td>
             <td></td>
             <td>29</td>
             <td>swj@qq.com</td>
             <td><a href="#">删除</a></td>
         </tr>
     </tbody>
 </table>
</div>
<script type="text/javascript">
 const add = document.getElementById('add');
 const tbody = document.getElementById('tbody');
 // 添加按钮的点击事件
 add.onclick = function () {
     // 取输入文本框的值
     const name = document.getElementById('name').value;
     const sex = document.getElementById('sex').value;
     const age = document.getElementById('age').value;
     const email = document.getElementById('email').value;
     //这种写法容易被xss攻击
     /* tbody.insertAdjacentHTML("beforeend",
             `
             <tr>
                 <td>${name}</td>
                 <td>${sex}</td>
                 <td>${age}</td>
                 <td>${email}</td>
                 <td><a href="javascript:;">删除</a></td>
 			</tr>
             `
         ) */
     //方法二:
     //创建元素
     const tr=document.createElement("tr")
     //创建td
     const nameTd=document.createElement("td")
     const sexTd=document.createElement("td")
     const ageTd=document.createElement("td")
     const emailTd=document.createElement("td")
     //添加文本
     nameTd.textContent=name
     sexTd.textContent=sex
     ageTd.textContent=age
     emailTd.textContent=email
     //将三个td添加到tr中
     tr.appendChild(nameTd)
     tr.appendChild(sexTd)
     tr.appendChild(ageTd)
     tr.appendChild(emailTd)
     tr.insertAdjacentHTML("beforeend",'<td><a href="javascript:;">删除</a></td>')
     tbody.appendChild(tr)
     //由于上边的超链接是新添加的,所以它的上边并没有绑定单级响应函数,所以新添加的员工无法删除
     //解决方式:为新添加的超链接单独绑定响应函数
     links[links.length-1].onclick=delEmpHandler
     // 点击添加后,清空输入框的内容
     document.getElementById("name").value = "";
     document.getElementById("sex").value = "";
     document.getElementById("age").value = "";
     document.getElementById("email").value = "";
 }

 // 获取所有的超链接
 const links = document.links
 //删除数据函数
 function delEmpHandler(){
     const tr=this.parentNode.parentNode
     //获取要删除的员工的姓名
     //const empName=tr.getElementByTagName("td")[0].textContent
     const empName=tr.firstElementChild.textContent

     //弹出提示
     if (confirm("你确定要删除【"+empName+"】这条数据吗?")) {
         //删除tr
         tr.remove()   
     }
     //本练习中的超链接,我们是不希望发生跳转,但是跳转行为是超链接的默认行为
     //只要点击超链接就会触发页面的跳转,事件中可以通过取消默认行为来阻止超链接的跳转
     //使用return false来取消默认行为,只在xxX.xXx = function()丹这种形式绑定的事件中才适用
     //href:"javascript:;"
     return false
 }
 //为其绑定单击响应函数
 for (let i = 0; i < links.length; i++) {
     links[i].onclick=delEmpHandler
 }
</script>

2).练习二:

全选效果

<form action="">
 <p>你的爱好是?</p>
 <input type="checkbox" id="qx_qbx">全选/全不选<br>
 <input type="checkbox" name="items" value="足球">足球<br>
 <input type="checkbox" name="items" value="篮球">篮球<br>
 <input type="checkbox" name="items" value="羽毛球">羽毛球<br>
 <input type="checkbox" name="items" value="乒乓球">乒乓球<br>
 <input type="button" id="qx" value="全选">
 <input type="button" id="qbx" value="全不选">
 <input type="button" id="fx" value="反选">
 <input type="button" id="tj" value="提交">
</form>
<script type="text/javascript">
 var qx=document.getElementById("qx");
 var items=document.getElementsByName("items");
 //获取全选/全不选的多选框
 var qx_qbx=document.getElementById("qx_qbx");

 var qx=document.getElementById("qx");
 qx.onclick=function(){
     for(var i=0;i<items.length;i++){
         items[i].checked=true;
     }
     //将qx_qbx设置为选中状态
     qx_qbx.checked=true;
 };

 var qbx=document.getElementById("qbx");
 qbx.onclick=function(){
     for(var i=0;i<items.length;i++){
         items[i].checked=false;
     }
     //将qx_qbx设置为选中状态
     qx_qbx.checked=false;
 };

 var fx=document.getElementById("fx");
 fx.onclick=function(){
     //将qx_qbx设置为选中状态
     qx_qbx.checked=true;
     for(var i=0;i<items.length;i++){
         items[i].checked=!items[i].checked;
         //在反选时也需要判断是否全都选中
         //判断四个多选框是否全选
         //只要有一个没选中则就不是全选
         if(!items[i].checked){
             //一旦进入判断,则证明不是全选状态
             //将qx_qbx设置为没选中状态
             qx_qbx.checked=false;
         }
     }
 };

 var tj=document.getElementById("tj");
 tj.onclick=function(){
     for(var i=0;i<items.length;i++){
         if(items[i].checked){
             alert(items[i].value);
         }

     }
 };

 qx_qbx.onclick=function(){
     for(var i=0;i<items.length;i++){
         items[i].checked=this.checked;
     }
 };
 //为四个多选框分别绑定点击响应函数
 for(var i=0;i<items.length;i++){
     items[i].onclick=function(){
         //将qx_qbx设置为选中状态
         qx_qbx.checked=true;
         for(var j=0;j<items.length;j++){
             //判断四个多选框是否全选
             //只要有一个没选中则就不是全选
             if(!items[j].checked){
                 //一旦进入判断,则证明不是全选状态
                 //将qx_qbx设置为没选中状态
                 qx_qbx.checked=false;
                 //一旦进入判断,则已经得出结果,不用再继续执行循环
                 break;
             }
         }
     }
 };
</script>

3).练习三:

图片切换

<style type="text/css">
 *{
     margin: 0;
     padding: 0;
 }
 #outer{
     width: 500px;
     margin: 50px auto;
     padding: 10px;
     background-color: aqua;
     text-align:center ;
 }
 #outer img{
     width: 500px;
 }
</style>
<script type="text/javascript">
 window.onload=function(){
     //点击按钮切换图片
     //要切换图片就是要修改标签的src属性
     //获取img标签
     var img=document.getElementsByTagName("img")[0];
     //创建一个数组,用来保存图片的路径
     var imgArr=["../img/1.jpg","../img/2.jpg","../img/3.jpg","../img/4.jpg","../img/5.jpg"];
     //创建一个变量,来保存当前正在显示的图片的索引
     var index=0;
     //获取id为info的p元素
     var info=document.getElementById("info");
     //设置提示文字
     info.innerHTML="一共"+imgArr.length+"张图片,当前是第"+(index+1)+"张";
     //获取两个按钮
     var prev=document.getElementById("prev");
     var next=document.getElementById("next");
     //分别为两个按钮绑定单击响应函数
     prev.onclick=function(){
         index--;
         if(index<0){
             index=imgArr.length-1;
         }
         img.src=imgArr[index];
         info.innerHTML="一共"+imgArr.length+"张图片,当前是第"+(index+1)+"张";
     };
     next.onclick=function(){
         index++;
         if(index>imgArr.length-1){
             index=0;
         }
         img.src=imgArr[index];
         info.innerHTML="一共"+imgArr.length+"张图片,当前是第"+(index+1)+"张";
     };
 }
</script>
<p id="info"></p>
<div id="outer">
 <img src="../img/1.jpg" alt="m1">
 <button id="prev">上一张</button>
 <button id="next">下一张</button>
</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值