DOM
dom
DOM(Document Object Model),文档对象模型。
通过dom模型可以让sj操作页面中的html标签和样式,从而改变页面的结构和样式
- document(文档):表示整个html网页文件(各种标签)
html标签存在完整的层次结构
- object(对象):当浏览器将html加载到内存中会自动生成每个标签对应的对象,以便js可以对象。js操作对象相当于操作标签。
操作对象:获取更改属性,调用方法
-
model(模型):html存在层次结构,生成的对象也会存在层次结构。这种层次结构被称为模型,即对象之间的关系。
-
节点(Node):构成html文档的基本单元,网页中的所有内容都是节点。整个文档也是一个节点
节点分类:文档节点(整个html文档),元素节点(html文档中的标签),属性节点(标签的属性),文本节点(标签中的文本内容)
节点不同,属性和方法不同。
浏览器中已经提供了文档节点对象,这个对象可以直接使用,也是window的对象。
document对象代表的是整个页面
浏览器加载html文件后自动创建的document对象,就是文档节点对象。
//通过id获取button按钮对应的dom属性
var btn = document.getElementById("btn");
//操作属性
btn.innerHtml = "点击按钮";
//操作
btn.onclick = function(){
alert("被点击");
}
- 通过dom模型获取需要操作的对象。
- 调用对象对应的属性或方法,通过逻辑动态改变页面的效果。
事件
事件:用户与浏览器直接的交互行为,某些场景下发生的“事情”;比如:点击,双击,关闭等
事件关注的三个方面:
- 事件源:事件产生的来源;
- 事件:发生的“事件”本身,当事件被触发,浏览器会自动产生事件对象
- 事件处理(回调函数):事件发生后被调用的函数。
在html元素上设置属性的方式来监听事件,结构(html)和事件(js)进行了耦合,不方便维护,可以进行拆分,推荐拆分的方式处理。
使用拆分的方式处理页面中标签绑定的事件:
- 获取页面的标签对象
- 设置事件,绑定事件处理(回调函数)
<button id="btn">
</button>
<script>
//获取标签对象
var btn = document.getElementById('btn');
//设置事件属性,绑定回调函数---事件发生时,函数才调用
btn.onclick = () => {
//逻辑代码
alert("btn被点击");
}
</script>
页面加载
浏览器在加载页面时,由上而下顺序加载,读一行执行一行。
如果script标签写在页面的上方,则html还没被读取,通过js获取的标签对象就会为null,所以我们需要在 页面加载完毕之后,再执行js代码,读取页面中的标签。
将js代码在访问页面加载之后时间之后执行,使用window.onload事件。
<button id="btn">
</button>
<script>
window.onload = function(){
//获取标签对象
var btn = document.getElementById('btn');
//设置事件属性,绑定回调函数---事件发生时,函数才调用
btn.onclick = () => {
//逻辑代码
alert("btn被点击");
}
}
</script>
dom查询
-
通过document对象的方法查询dom节点
- getElememtById(id)
- 根据ID获取指定的节点对象
- 返回一个结点对象或null
- getElementByTagName()
- 根据标签名称获取一组节点对象
- 返回值为数组对象,即使一个元素也会封装到数组中返回
- getElementByName(name值)
- 根据标签name的值获取一组元素节点对象
- 返回值为数组对象
- document.body:获取body标签。
- document.documentElement:获取html标签。
- document.all:获取所有标签。
- document.getElementByClassName(类名):获取类标签。
- document.querySelect(选择器):获取一个标签。
- document.querySelectAll(选择器):获取一类标签,返回一个伪数组。
innerHTML:(属性)
获取元素内部的html代码。
- getElememtById(id)
-
通过层级节点查询
元素.getElementsByTagName(标签名);
- 根据标签名称获取当前元素下的所有子节点。
- 返回当前节点指定标签下的后代节点。
元素.childNodes
- 返回包括文本节点在内的所有子节点。
- DOM规定,标签和标签之间的空白也会成为文本节点。
元素.children
- 返回当前元素下的所有子元素,不包括空白文本。
元素.firstChild / 元素.childNodes[0]
- 返回当前元素下的第一个节点,包括空白文本节点。
元素.firstElementChild
- 返回当前元素下的第一个子元素,排除空白节点。
节点.nodeName : 获取节点名称
节点.nodeType : 获取节点类型
节点.nodeValue : 获取节点值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body {
width: 800px;
margin-left: auto;
margin-right: auto;
}
button {
width: 300px;
margin-bottom: 10px;
}
#btnList {
float: left;
}
#total {
width: 450px;
float: left;
}
ul {
list-style-type: none;
margin: 0px;
padding: 0px;
}
.inner li {
border-style: solid;
border-width: 1px;
padding: 5px;
margin: 5px;
background-color: #99ff99;
float: left;
}
.inner {
width: 400px;
border-style: solid;
border-width: 1px;
margin-bottom: 10px;
padding: 10px;
float: left;
}
</style>
<script>
window.onload = function(){
//为btn01绑定单击事件
var btn01 = document.getElementById('btn01');
// alert(btn01);
btn01.onclick = function(){
//查找#bj节点 --- li元素
var bj = document.getElementById('bjx');
// alert(bj);
// console.log(bj);
//获取li中的文本内容
// console.log(bj.innerHTML);
};
//为btn02绑定点击事件
var btn02 = document.getElementById("btn02");
btn02.onclick = function(){
//查找所有的li节点
var lis = document.getElementsByTagName("li");
// console.log(lis); //HTMLCollection
// console.log(lis.length); //获取数组的长度
//循环遍历元素
for(var i = 0; i < lis.length; i++){
console.log(lis[i].innerHTML); //获取的包含html
}
};
//为btn03绑定点击事件
var btn03 = document.getElementById("btn03");
btn03.onclick = function(){
//查找name=gender的所有节点
var inputs = document.getElementsByName("gender");
/*
描述:
- 如果需要获取元素节点的属性
直接使用:元素.属性名
注意:class属性需要:元素.className
*/
//返回的数组
// console.log(inputs.length);
for(var i = 0; i < inputs.length; i++){
//获取input标签的value值
console.log(inputs[i].value, inputs[i].type, inputs[i].name, inputs[i].className);
}
};
//获取city下的所有li
//获取btn04的节点
var btn04 = document.getElementById("btn04");
//为btn04绑定点击事件
btn04.onclick = function(){
// 获取city节点
var city = document.getElementById("city");
// 获取city下的所有li节点
var lis = city.getElementsByTagName("li");
console.log(lis);
for(var i = 0;i < lis.length;i++){
console.log(lis[i].innerHTML);
}
};
// 获取city写的所有子节点
//获取btn05的节点
var btn05 = document.getElementById("btn05");
//为btn04绑定点击事件
btn05.onclick = function(){
// 获取city节点
var city = document.getElementById("city");
// 获取city下的所有li节点
var allNodes = city.childNodes;
var allNodes02 = city.children;
console.log(allNodes);
console.log(allNodes02);
for(var i = 0;i < allNodes.length;i++){
console.log(allNodes[i].innerHTML);
};//有空白文本
for(var i = 0;i < allNodes02.length;i++){
console.log(allNodes02[i].innerHTML);
}//没有空白文本
};
//返回phone的第一个子节点
// 获取btn06的节点
var btn06 = document.getElementById("btn06");
btn06.onclick = function(){
var phone = document.getElementById("phone");
var first = phone.firstChild;//第一个子节点,包括空白文本
var first02 = phone.firstElementChild;//返回第一个子节点,不包括空白文本
console.log(first);
console.log(first02);
};
//返回bj的父节点
// 获取btn07的节点
var btn07 = document.getElementById("btn07");
btn07.onclick = function(){
var bj = document.getElementById("bj");
var parent = bj.parentNode;
var parent02 = bj.parentElement;
console.log(parent);
console.log(parent02);//两个返回值相同
console.log(parent.innerHTML);//返回带标签
console.log(parent.innerText);//返回文本内容不带标签
};
// 返回#android的前一个兄弟节点
var btn08 = document.getElementById("btn08");
btn08.onclick = function(){
var android = document.getElementById("android");
var bro = android.previousSibling;//返回空白文本
var bro02 = android.previousElementSibling;//返回<li>IOS</li>
var bro03 = android.nextSibling;//返回空白文本
var bro04 = android.nextElementSibling;//返回<li>Windows Phone</li>
console.log(bro);
console.log(bro02);
console.log(bro03);
console.log(bro04);
};
// 返回#username的value属性值
var btn09 = document.getElementById("btn09");
btn09.onclick = function(){
var username = document.getElementById("username");
var value = username.value;
console.log(value);
};
// 设置#username的value属性值
var btn10 = document.getElementById("btn10");
btn10.onclick = function(){
var username = document.getElementById("username");
username.value="ccccccc";
};
//返回#bj的文本值
var btn11 = document.getElementById("btn11");
btn11.onclick = function(){
var bj = document.getElementById("bj");
console.log(bj.innerText);
};
};
</script>
</head>
<body>
<dl>
</dl>
<div id="total">
<div class="inner">
<p>
你喜欢哪个城市?
</p>
<ul id="city">
<li id="bj"><a href="#">北京</a></li>
<li>上海</li>
<li>东京</li>
<li>首尔</li>
</ul>
<br>
<br>
<p>
你喜欢哪款单机游戏?
</p>
<ul id="game">
<li id="rl">红警</li>
<li>实况</li>
<li>极品飞车</li>
<li>魔兽</li>
</ul>
<br />
<br />
<p>
你手机的操作系统是?
</p>
<ul id="phone">
<li>IOS</li>
<li id="android">Android</li>
<li>Windows Phone</li>
</ul>
</div>
<div class="inner">
gender:
<input class="hello" type="radio" name="gender" value="male" />
男
<input class="hello" type="radio" name="gender" value="female" />
女
<br>
<br>
name:
<input type="text" name="name" id="username" value="abcde" />
</div>
</div>
<div id="btnList">
<div><button id="btn01">查找#bj节点</button></div>
<div><button id="btn02">查找所有li节点</button></div>
<div><button id="btn03">查找name=gender的所有节点</button></div>
<div><button id="btn04">查找#city下所有li节点</button></div>
<div><button id="btn05">返回#city的所有子节点</button></div>
<div><button id="btn06">返回#phone的第一个子节点</button></div>
<div><button id="btn07">返回#bj的父节点</button></div>
<div><button id="btn08">返回#android的前一个兄弟节点</button></div>
<div><button id="btn09">返回#username的value属性值</button></div>
<div><button id="btn10">设置#username的value属性值</button></div>
<div><button id="btn11">返回#bj的文本值</button></div>
</div>
</body>
</html>
dom增删改
- document.createElement(标签名);
创建元素节点对象 - document.createTextNode(‘文本内容’);
创建文本节点对象 - 父节点.appendChild(子节点);
向父节点中添加一个子节点 - 父节点.insertBefore(新节点, 旧节点);
将指定的子节点前插入新的子节点 - 父节点.replaceChild(新节点, 旧节点);
使用指定的子节点替换已有的子节点 - 父节点.removeChild(子节点);
子节点.parentNode.removeChild(子节点);
删除指定的子节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
window.onload =function(){
/*
参数:
id : 标签的id值
callBack: 回调函数
*/
var $ = function(id, callBack) {
var btn = document.getElementById(id);
btn.onclick = callBack;
};
// 添加成都
$('add',function(){
//创建li节点 ---- <li>成都</li>
var li = document.createElement('li');
//创建文本节点
var txt = document.createTextNode('成都');
//将文本节点添加到li节点中
li.appendChild(txt);
//将创建的li添加到页面中 --- ul中
var ul = document.getElementById('city');
ul.appendChild(li);
});
//添加广州节点到西安之上
$('insert', function(){
//创建广州节点
var li = document.createElement('li');
var txt = document.createTextNode('广州');
li.appendChild(txt);
//获取西安节点
var xian = document.getElementById('xian');
var city = document.getElementById('city');
city.insertBefore(li, xian);
});
//使用广州节点替换西安节点
$('replace',function(){
//创建广州节点
var li = document.createElement('li');
var txt = document.createTextNode('广州');
li.appendChild(txt);
//获取西安节点
var xian = document.getElementById('xian');
var city = document.getElementById('city');
city.replaceChild(li, xian);
});
//删除西安节点
$('delete',function(){
//获取西安节点
var xian = document.getElementById('xian');
// var city = document.getElementById('city');
// city.removeChild(xian);
xian.parentNode.removeChild(xian);
});
//获取#city内的HTML代码
$('findHTML', function(){
var city = document.getElementById('city');
alert(city.innerHTML);
});
//设置#xian下的HTML代码
$('setHTML', function(){
var xian = document.getElementById('xian');
// xian.innerHTML = '小寨';
xian.innerHTML = '<a href="#">小寨 </a>';
});
//使用innerHTML创建节点
$('createHTML', function(){
//使用innerHTML创建广州节点
var city = document.getElementById('city');
city.innerHTML += '<li>广州</li>';
//使用两种方式结合
var guangzhou = document.createElement('li');
guangzhou.innerHTML = '广州';
city.appendChild(guangzhou);
});
};
</script>
<ul id="city">
<li>北京</li>
<li>上海</li>
<li id="xian">西安</li>
</ul>
<button id="add">添加成都</button>
<button id="insert">添加广州节点到西安之上</button>
<button id="replace">使用广州节点替换西安节点</button>
<button id="delete">删除西安节点</button>
<button id="findHTML">获取#city内的HTML代码</button>
<button id="setHTML">设置#xian下的HTML代码</button>
<button id="createHTML">使用innerHTML创建节点</button>
</body>
</html>
样式操作
通过元素.style可以获取当前标签对应的样式对象。
通过style样式对象可以对css样式进行修改。
style.样式名只能获取内联样式。
通过元素.style修改的样式为标签的内联样式。
样式命名规则:
如果css中的样式存在横杠(-),则去掉-,使用驼峰命名法。如:background-color转换为backgroundColor。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div{
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div style="width: 200px;"></div>
<script>
window.onload = function(){
var div = document.getElementsByTagName('div')[0];
div.onclick = function (){
console.log(div.style);
div.style.backgroundColor = 'green';
}
}
</script>
</body>
</html>
获取内部样式
IE浏览器:通过 元素.currentStyle.样式名 的方式只有IE浏览器可以获取相应的样式。
其它浏览器:
getcomputedStyle(元素,null)
参数:
第一个参数:需要获取元素的样式对象
第二个参数:可以创建一个伪元素,一般都用null
返回样式对象,对象中封装了元素对应的样式信息
样式对象.样式名称:获取具体信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div{
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div></div>
<script>
window.onload = function(){
var div = document.getElementsByTagName("div")[0];
//IE浏览器
//console.log(div.currentStyle);
//console.log(div.currentStyle.width);
//console.log(div.currentStyle.height);
//其它浏览器,IE8以下不支持
var styleObj = window.getComputedStyle(div,null)
console.log(styleObj);
console.log(styleObj.width);
console.log(styleObj.height);
styleObj.width = '300px';
styleObj.height = '300px';
}
</script>
</body>
</html>
通过 元素.currentStyle.或get computedStyle获取的样式信息为只读信息,不能修改
styleObj.width = '300px';
styleObj.height = '300px';
创建函数返回具体样式(考虑兼容)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div{
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div></div>
<script>
window.onload = function(){
var div = document.getElementsByTagName("div")[0];
var w = getStyle(div,'width');
function getStyle(obj,styleName){
//非IE8以下
if(window.getComputedStyle){
return window.getComputedStyle(div,null)[styleName];
}else{
//IE8以下
return obj.currentStyle[styleName];
}
}
console.log(w);
}
</script>
</body>
</html>
getComputedStyle参数:
obj:需要获取样式的元素
styleName:样式名称
修改样式封装
通过修改class的值可以一次修改多种样式
修改时需要使用 元素.className
通过 +=和空格可以添加多个class
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.boxRed {
width: 200px;
height: 200px;
background-color: red;
}
.boxYellow{
width: 300px;
height: 300px;
background-color: yellow;
}
.boxSize{
font-size: 20px;
color: white;
}
</style>
</head>
<body>
<button id="btn">修改样式</button>
<div id="box" class="boxRed">字体</div>
<script>
window.onload = function(){
var btn = document.getElementById('btn');
// var box = document.getElementById('box');
btn.onclick = function(){
//更改样式
var div = document.getElementById('box');
//修改class值
//添加boxYellow类
div.className = 'boxYellow';
//添加boxSize类
div.className += ' boxSize';
}
}
</script>
</body>
</html>
元素大小和偏移量
clientWidth/clientHeight
获取元素的可见高度和宽度
返回的属性值不带px,是一个数字,可以直接进行运算
包括内容区和内边距,不带边框
属性为只读属性,不能更改。
offsetWidth/offsetHeight
和clientWidth相似,只是带边框
offsetParent
获取离当前元素最近的开启了定位的祖先元素
如果所有祖先元素没有定位则返回body
offsetLeft/offsetTop
获取当前元素相对于其定位的父元素的水平/垂直偏移量
scrollWidth/scrollHeight
获取元素整个滚动区域的宽度和高度
scrollLeft/scrollTop
获取元素水平或垂直滚动条滚动的距离
事件对象
onmouseover:鼠标移动事件
事件对象:
当事件响应函数被触发时,浏览器会生成一个和事件本身相关联的对象传递给回调函数。这个对象包含了事件的一切信息,比如鼠标的坐标,按键的值等等。这个对象被称为事件对象
事件对象由系统自动产生
clientX、clientY 获取鼠标指针的水平坐标和垂直坐标
window.onload = function(){
var $ = function(id){
return document.getElementById(id);
};
//鼠标绑定移动事件
$('box').onmousemove = function(e){ //e为事件本身(事件对象)
var x = e.clientX;
var y = e.clientY;
console.log(x + "---" + y);
};
};
事件冒泡
事件冒泡就是事件向上传导机制,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
如果不希望事件冒泡,则可以通过事件对象取消冒泡:事件对象.cancelBubble = true;
开发中事件冒泡大多数有用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box{
width: 200px;
height: 200px;
background-color: red;
}
#sp {
background-color: yellow;
}
</style>
</head>
<body>
<script src="tool.js"></script>
<script>
window.onload = function(){
//获取span标签对象
var span = $('sp');
span.onclick = function(e){
console.log('span被点击');
//取消事件
e.cancelBubble = true;
};
//获取div标签对象
var div = $('box');
div.onclick = function(){
console.log('div被点击');
};
//获取body标签对象
var body = document.body;
body.onclick = function(){
console.log('body被点击');
}
};
</script>
<div id="box">
div文本
<span id="sp">span文本</span>
</div>
</body>
</html>
事件委托
将事件统一绑定为祖先元素,当后代元素上的事件被触发时,会一直冒泡到祖先元素上,从而通过祖先元素的回调函数来处理事件
事件委托是利用了事件的冒泡机制,委托可以减少事件的绑定次数,提高程序的性能。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="tool.js"></script>
<script>
window.onload = function () {
//获取所有a标签
var all = document.getElementsByTagName('a');
var ul = $('add');
//添加li标签
$('btn').onclick = function () {
/*
每创建一个新的a标签,多需要重新绑定点击事件
*/
var li = document.createElement('li');
li.innerHTML = '<a href="javascript:;" class="link">连接四</a>';
ul.append(li);
};
//统一给父元素绑定一次事件
ul.onclick = function (e) {
//判断是否为a标签
if(e.target.className == 'link'){
console.log('a被点击');
};
};
};
</script>
<button id="btn">添加链接</button>
<ul id="add" style="background-color: #ccc">
<li><a href="javascript:;" class="link">连接一</a></li>
<li><a href="javascript:;" class="link">连接二</a></li>
<li><a href="javascript:;" class="link">连接三</a></li>
</ul>
</body>
</html>
事件绑定
-
元素对象.事件名称 = 回调函数
一个元素的相同事件只能绑定一次响应函数,不能绑定多个,如果绑定多个,后面的会覆盖前面的。
-
元素.addEventListener()–IE8以下不支持
参数:
-
事件字符串:去掉on;
- 回调函数:事件触发时需要相应的函数
- 是否在捕获阶段触发事件,boolean类型,一般设置为false
一个元素的相同事件可以多次绑定,执行的顺序为绑定的顺序。
-
-
元素.attachEvent()—IE8以下支持,其他浏览器不支持
参数:
- 事件字符串:需要on
- 回调函数:事件触发时需要相应的函数
一个元素的相同事件可以多次绑定,执行顺序和绑定顺序相反。
window.onload = function(){
var input = document.getElementById('btn');
//使用元素.事件名称 = 回调函数
input.onclick = function(){
console.log('被点击1');
};
//再次绑定
input.onclick = function(){
console.log('被点击2');
}
//不同事件
input.onmouseover = function(){
console.log('鼠标悬浮');
}
//使用addEventListener方式
//给input绑定点击事件
input.addEventListener("click", function(){
console.log('被点击1');
}, false);
input.addEventListener("click", function(){
console.log('被点击2');
}, false);
/*
IE8之下使用
*/
input.attachEvent('onclick', function(){
console.log('被点击1');
});
input.attachEvent('onclick', function(){
console.log('被点击2');
});
bind(input, "click", function(){
console.log("==============");
});
/*
绑定事件自定义函数
参数:
- obj: 需要绑定的事件对象
- eventStr: 事件名称 不带on
- callBack: 回调函数
*/
function bind(obj, eventStr, callBack){
//非ie8浏览器
if(obj.addEventListener){
obj.addEventListener(eventStr, callBack, false);
}else {
obj.attachEvent("on" + eventStr, function(){
callBack.call(obj);
});
}
}
};
事件传播
- 网景和微软对事件的传播有不同的实现方式
微软:事件由内向外传播(先触发当前元素,再向祖先元素传播),也被成为事件冒泡。
网景:事件由外向内传播(先触发当前元素最外层的祖先元素,再向子元素传播,直到当前元素停止),也不称为事件捕获阶段。
-
W3C将事件分为三个阶段
-
捕获阶段:从最外层的祖先元素,向目标元素进行实际的捕获,但默认不执行回调函数。
-
目标阶段:事件捕获到目标元素,捕获结束,开始在目标元素上触发事件。
-
冒泡阶段:事件从目标元素向祖先元素传递,依次触发祖先元素上的事件。
-