前端学习第十天——使用javascript操作html
Dom简介
DOM(Document Object Model,文档对象模型)是JavaScript操作HTML文档的接口,是文档操作变得非常优雅、简洁。
nodeType常用属性值
节点的nodeType属性可以显示这个节点具体的类型
nodeType值 | 节点类型 |
---|---|
1 | 元素节点,例如<p> 和<div> |
3 | 文字节点 |
8 | 注释节点 |
9 | document节点 |
10 | DTD节点 |
访问元素节点的常用方法
方法 | 功能 | 兼容性 |
---|---|---|
document.getElementById() | 通过 id 得到元素 | IE6 |
document.getElementsByTagName() | 通过 标签名 得到元素数组 | IE6 |
document.getElementsByClassName() | 通过 类名 得到元素数组 | IE9 |
document.querySelector() | 通过 选择器 得到元素 | IE8部分兼容 IE9完全兼容 |
document.querySelectorAll() | 通过 选择器 得到元素数组 | IE8部分兼容 IE9完全兼容 |
可以使用window.onload = function(){}
事件,使页面加载完毕后,在执行指定代码
节点的关系
文本节点也属于节点
关系 | 考虑所有节点 | 只考虑元素节点 |
---|---|---|
子节点 | childNodes | children |
父节点 | parentNode | parentNode |
第一个子节点 | firstChild | firstElementChild |
最后一个子节点 | lastChild | lastElementChild |
前一个兄弟节点 | previousSibling | previousElementSibling |
后一个兄弟节点 | nextSibling | nextElementSibling |
封装节点常用函数
<script>
// 封装一个函数,这个函数可以返回元素的所有子元素节点(兼容到IE6),类似children的功能
function getChildren(node) {
// 结果数组
var children = [];
// 遍历node这个节点的所有子节点,判断每一个子节点的nodeType属性是不是1
// 如果是1,就推入结果数组
for (var i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].nodeType == 1) {
children.push(node.childNodes[i]);
}
}
return children;
}
// 封装一个函数,这个函数可以返回元素的前一个元素
兄弟节点(兼容到IE6),类似previousElementSibling的功能
function getElementPrevSibling(node) {
var o = node;
// 使用while语句
while (o.previousSibling != null) {
if (o.previousSibling.nodeType == 1) {
// 结束循环,找到了
return o.previousSibling;
}
// 让o成为它的前一个节点,就有点“递归”的感觉
o = o.previousSibling;
}
return null;
}
// 封装第三个函数,这个函数可以返回元素的所有元素兄弟节点
function getAllElementSibling(node) {
// 前面的元素兄弟节点
var prevs = [];
// 后面的元素兄弟节点
var nexts = [];
var o = node;
// 遍历node的前面的节点
while(o.previousSibling != null) {
if(o.previousSibling.nodeType == 1){
prevs.unshift(o.previousSibling);
}
o = o.previousSibling;
}
o = node;
// 遍历node的后面的节点
while(o.nextSibling != null) {
if(o.nextSibling.nodeType == 1){
nexts.push(o.nextSibling);
}
o = o.nextSibling;
}
// 将两个数组进行合并,然后返回
return prevs.concat(nexts);
}
</script>
改变元素节点的内容
innerHTML
属性能以HTML语法设置节点中的内容
innerText
属性只能以纯文本的形式设置节点的内容
改变元素节点的CSS样式
CSS属性要写成驼峰式
oBox.style.fontSize='32px'
不符合W#C标准的属性,要使用setAttribute()
和getAttribute()
来设置和读取
oBox.setAttribute('data-n',10);
var n = oBox.getAttribute('data-n');
节点的创建
document.createElement()
方法用于创建一个指定的tagname
的HTML元素
var oDiv = document.createElement('div');
创建出来的节点是“孤儿节点”,它并没有挂载在DOM树上。必须使用appendChild()
和insertBefore()
方法将孤儿节点插入到DOM树上
-
appendChild()
任何在DOM树上的节点,都可以调用appendChild()
方法,它可以将孤儿节点挂载到他的内部,成为它的最后一个子节点。
父节点.appendChild(孤儿节点);
-
insertBefore()
任何在DOM树上的节点,都可以调用insertBefore()
方法,它可以将孤儿节点挂载到它的内部,成为它的“标杆子节点”之前的节点。
父节点.insertBefore(孤儿节点,标杆节点);
移动节点
如果将已经挂载到树上的DOM树上的节点成为appendChild()
和insertBefore()
的参数,这个节点将会移动。
新父节点.appendChild(已经有父亲的节点);
新父节点.insertBefore(已经有父亲的节点,标杆子节点);
一个节点不能同时位于DOM树的两个位置
删除节点
removeChild()
方法从DOM中删除一个子节点
父节点.removeChild(要删除子节点);
克隆节点
cloneNode()
方法可以克隆节点,克隆出的节点是“孤儿节点”
var 孤儿节点 = 老节点.cloneNode();
参数是一个布尔值,表示是否采用深度克隆:如果为true,则表示该节点的所有后代节点也会被克隆,如果为false,则只克隆该节点本身。
var 孤儿节点 = 老节点.cloneNode(true);
事件监听
- 鼠标事件监听
事件名 | 事件描述 |
---|---|
onclick | 当鼠标单击某个对象 |
ondbclick | 当鼠标双击某个对象 |
onmousedown | 当鼠标按键在某个对象上被按下 |
onmouseup | 当鼠标按键在某个对象上被松开 |
onmousemove | 当鼠标按键在某个对象上被移动 |
onmouseenter | 当鼠标进入某个对象 |
onmouseleave | 当鼠标离开某个对象 |
- 键盘事件监听
事件名 | 事件描述 |
---|---|
onkeypress | 当某个键盘的健被按下(系统按钮如箭头键和功能键无法得到识别) |
onkeydown | 当某个键盘的健被按下(系统按钮可以识别,并且会先于onkeypress ) |
onkeyup | 当键盘的键被松开 |
- 表单监听事件
事件名 | 事件描述 |
---|---|
onchange | 当用户改变域的内用 |
onfoucs | 当某元素获得焦点 |
onblur | 当某元素失去焦点 |
onsubmit | 当表单被提交 |
onreset | 当表单被重置 |
oninput | 当表单正在被输入 |
- 页面时间监听
事件名 | 事件描述 |
---|---|
onload | 当页面加载完 |
onunload | 当用户退出页面 |
事件的传播
先从外到内,然后后再从内到外。(捕获阶段————冒泡阶段)
onxxx这样的写法只能监听冒泡阶段
DOM0级事件监听:只能监听冒泡阶段
oBox.onclick = function(){
}
DOM2级事件监听:
oBox.addEventListener('click',function(){
// 事件处理函数
},true); //true监听捕获阶段,false监听冒泡阶段
实验代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box1{
width: 202px;
height: 202px;
border: 1px solid #000;
padding: 50px;
}
#box2{
width: 100px;
height: 100px;
border: 1px solid #000;
padding: 50px;
}
#box3{
width: 100px;
height: 100px;
border: 1px solid #000;
}
</style>
</head>
<body>
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
<script>
var oBox1 = document.getElementById('box1');
var oBox2 = document.getElementById('box2');
var oBox3 = document.getElementById('box3');
oBox2.addEventListener('click', function() {
console.log('我是box2的冒泡阶段');
}, false);
// DOM规定最内层元素不分先捕获还是先冒泡,所以最层的输出会跟代码书写顺序相关
oBox3.addEventListener('click', function() {
console.log('我是box3的捕获阶段');
}, true);
oBox3.addEventListener('click', function() {
console.log('我是box3的冒泡阶段');
}, false);
oBox3.onclick = function () {
console.log('我是box3的onclick');
};
oBox1.addEventListener('click', function() {
console.log('我是box1的冒泡阶段');
}, false);
oBox2.addEventListener('click', function() {
console.log('我是box2的捕获阶段');
}, true);
oBox1.addEventListener('click', function() {
console.log('我是box1的捕获阶段');
}, true);
oBox1.onclick = function () {
console.log('我是box1的onclick');
};
oBox2.onclick = function () {
console.log('我是box2的onclick');
};
</script>
</body>
</html>
- 注意事项
- 最内部元素不区分捕获阶段和冒泡阶段,会执行写在前面的监听,然后执行后写的监听。
- 如果给元素设置相同的两个或多个同名事件,则DOM0级写法后面写的会覆盖先写的,而DOM2级会按顺序执行。
事件对象
事件处理函数提供一个形式参数,它是一个对象,封装了本次事件的细节。这个参数通常用单词event或字母e表示
- 鼠标位置
属性 | 属性描述 |
---|---|
clientX | 鼠标指针相对于 浏览器 的水平坐标 |
clientY | 鼠标指针相对于 浏览器 的垂直坐标 |
pageX | 鼠标指针相对于 整张网页 的水平坐标 |
pageY | 鼠标指针相对于 整张网页 的垂直坐标 |
offsetX | 鼠标指针相对于 事件源元素 的水平坐标 |
offsetY | 鼠标指针相对于 事件源元素 的垂直坐标 |
e.charCode
属性通常用于onkeypress
事件中,表示用户输入的字符串的“字符码”
e.keyCode
属性通常用于onkeydown
事件和onkeyup
中,表示用户按下的按键的“键码”
charCode字符码
字符 | 字符码 |
---|---|
数字0~9 | 48~57 |
大写字母A~Z | 65~90 |
小写字母a~z | 97~122 |
keyCode键码
按键 | 键码 |
---|---|
数字0~9 | 48~57 |
字母不分大小写A~Z | 65~90 |
四个方向键←↑→↓ | 37、38、39、40 |
回车键 | 13 |
空格键 | 32 |
e.preventDefault()
方法用来阻止事件产生的默认动作
<body>
<p>
只能输入小写字母和数字:
<input type="text" id="field">
</p>
<script>
var oField = document.getElementById('field');
oField.onkeypress = function (e) {
console.log(e.charCode);
// 根据用户输入的字符的字符码(e.charCode)
// 数字0~9,字符码48~57
// 小写字母a~z,字符码97~122
if (!(e.charCode >= 48 && e.charCode <= 57 || e.charCode >= 97 && e.charCode <= 122)) {
// 阻止浏览器的默认行为
e.preventDefault();
}
};
</script>
</body>
e.stopPropagation()
方法用来阻止事件继续传播
<body>
<button id="btn">按我弹出弹出层</button>
<div class="modal" id="modal"></div>
<script>
var oBtn = document.getElementById('btn');
var oModal = document.getElementById('modal');
// 点击按钮的时候,弹出层显示
oBtn.onclick = function (e) {
// 阻止事件继续传播到document身上
e.stopPropagation();
oModal.style.display = 'block';
};
// 点击页面任何部分的时候,弹出层关闭
document.onclick = function () {
oModal.style.display = 'none';
};
// 点击弹出层内部的时候,不能关闭弹出层的,所以应该阻止事件继续传播
oModal.onclick = function (e) {
// 阻止事件继续传播到document身上
e.stopPropagation();
};
</script>
</body>
事件委托
利用事件冒泡机制,将后代元素事件委托给祖先元素。
事件委托通常需要结合使用e.target属性
属性 | 属性描述 |
---|---|
target | 触发此事件的最早元素,即“事件源元素” |
currentTarget | 事件处理程序附加到的元素 |
<body>
<button id="btn">按我创建一个新列表项</button>
<ul id="list">
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
</ul>
<script>
var oList = document.getElementById('list');
var oBtn = document.getElementById('btn');
oList.onclick = function (e) {
// e.target表示用户真正点击的那个元素
e.target.style.color = 'red';
};
oBtn.onclick = function () {
// 创建新的li元素
var oLi = document.createElement('li');
// 写内容
oLi.innerText = '我是新来的';
// 上树
oList.appendChild(oLi);
};
</script>
</body>
-
事件委托的使用场景
- 当有大量类似元素需要批量添加监听事件时,使用事件委托可以减少内存开销
- 当有动态元素节点上树时,使用事件委托可以让新上树的元素具有事件监听。
-
使用事件委托时需要注意的事项
- “不冒泡”相当于事件处理函数附加给了哪个DOM节点就是哪个DOM节点自己触发的事件,没有冒泡过程
- 最内层的元素不能再有额外的内层元素了
onmouseenter
不冒泡onmouseover
冒泡
定时器
setInterval()
函数可以重复调用一个函数,在每次调用之前具有固定的时间间隔。
setInterval(function(){
// 这个函数将自动被以固定间隔时间调用
},2000); // 2000是时间间隔,以毫秒为单位
setInterval()
函数可以接收更多的参数。
setInterval(function(a,b){
// 形式参数a的值是66,形式参数b的值是88
},2000,66,88);
具名函数也可以传入setInterval
setInterval(fun,1000);
清除定时器
clearInterval();
函数可以清除一个定时器
// 设置定时器,并用timer变量接收这个定时器
var timer = setInterval(function(){
},2000);
// 点击按钮时,清除定时器
oBtn.onclick = function(){
clearInterval(timer);
}
延时器
setTimeout()
函数可以设置一个延时器,当指定时间到了之后,会执行一次,不再重复执行
setTimeout(function(){
// 这个函数会在2秒后执行
},2000);
清除延时器
clearTimeout()
函数可以清除延时器
函数节流
函数节流:一个函数执行一次后,只有大于设定的执行周期后才允许执行第二次
var lock = true;
function 需要节流的函数(){
// 如果锁是关闭转态,则不执行
if(!lock){
return
}
// 函数核心语句
// 关锁
lock = false;
// 指定毫秒数后奖锁打开
setTimeout(function(){
lock = true;
},2000);
}