这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战
事件
• 事件:在什么时候做什么事
• 执行机制:触发--响应机制
• 绑定事件(注册事件)三要素:
-
事件源:给谁绑定事件
-
事件类型:绑定什么类型的事件 click 单击
-
事件函数:事件发生后执行什么内容,写在函数内部
事件监听
• JavaScript 解析器会给有绑定事件的元素添加一个监听,解析器会一直监测这个元素,只要触发对应的绑定事件,会立刻执行事件函数。
常用事件监听方法
• 方法1:绑定 HTML 元素属性。
<input type="button" id="btn" value="点击有惊喜" onclick="alert('点我做什么?')">
• 方法2:绑定 DOM 对象属性。
<input type="button" id="btn" value="点击有惊喜">
<script>
// 获取元素
var btn = document.getElementById("btn");
// 添加绑定事件
btn.onclick = function () {
// 定义的是事件被触发后要做的事情
alert("点我干嘛?");
};
</script>
常用的鼠标事件类型
onclick 鼠标左键单击触发
ondbclick 鼠标左键双击触发
onmousedown 鼠标按键按下触发
onmouseup 鼠标按键放开时触发
onmousemove 鼠标在元素上移动触发
onmouseover 鼠标移动到元素上触发 (从外界移动到元素上)
onmouseout 鼠标移出元素边界触发 (从元素上移动到外界)
onfocus 获得焦点
onblur 失去焦点
DOM 元素属性操作
非表单元素的属性
• 例如:href、title、id、src 等。
• 调用方式:元素对象打点调用属性名,例如 obj.href。
注意:
部分的属性名跟关键字和保留字冲突,会更换写法。
class → className
for → htmlFor
rowspan → rowSpan
• 属性赋值:给元素属性赋值,等号右侧的赋值都是字符串格式。
<img src="images/a.jpg" alt="美女" class="pic" id="pic">
<script>
// 等号赋值,值必须是字符串类型的
pic.src = "images/b.jpg";
</script>
获取标签内部内容的属性
• 获取标签内部内容的属性有两个:innerHTML 和 innerText
-
innerHTML属性,在获取标签内部内容时,如果包含标签,获取的内容会包含标签,获取的内容包括空白换行等。
-
innerText属性,在获取标签内部内容时,如果包含标签,获取的内容会过滤标签,获取的内容会去掉换行和缩进等空白。
<body>
<div id="box">
这是一个 div 标签
<span>这是一个 span 标签</span>
</div>
<script>
// 获取元素
var box = document.getElementById("box");
// 调用标签内部内容
console.log(box.innerHTML);
console.log(box.innerText);
</script>
更改标签内容
还可以通过两个属性给双标签内部去更改内容:
• innerHTML 设置属性值,有标签的字符串,会按照 HTML 语法中的标签加载。
<body>
<div id="box">
这是一个 div 标签
<span>这是一个 span 标签</span>
</div>
<script>
// 获取元素
var box = document.getElementById("box");
// 设置标签内部的内容
box.innerHTML = "<h2>hello JS</h2>";
</script>
• innerText 设置属性值,有标签的字符串,会按照普通的字符加载。
<body>
<div id="box">
这是一个 div 标签
<span>这是一个 span 标签</span>
</div>
<script>
// 获取元素
var box = document.getElementById("box");
// 设置标签内部的内容
box.innerText = "<h2>hello JS</h2>";
</script>
对比使用场景:
• innerText:在设置纯字符串时使用。
• innerHTML:在设置有内部子标签结构时使用。
表单元素属性
• value 用于大部分表单元素的内容获取(option除外)
• type 可以获取input标签的类型(输入框或复选框等)
• disabled 禁用属性
• checked 复选框选中属性
• selected 下拉菜单选中属性
<body>
<input type="button" value="按钮" id="btn"><br>
<input type="text" id="txt">
<select id="list">
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
</select>
<script>
// 获取元素
var btn = document.getElementById("btn");
var txt = document.getElementById("txt");
var list = document.getElementById("list");
var opts = list.getElementsByTagName("option");
// value 属性
console.log(btn.value);
console.log(txt.value);
console.log(opts[0].value);
console.log(opts[0].innerHTML);
</script>
// 更改 input 标签的 value
btn.value = "点击";
txt.value = "请输入内容"
注意: 在 DOM 中元素对象的属性值只有一个时,会被转成布尔值显示。
例如:txt.disabled = true;
// 表单元素特有的一些属性,属性名和属性值是一致的
console.log(txt.disabled);
btn.disabled = true;
自定义属性操作
• getAttribute(name) 获取标签行内属性
• setAttribute(name,value) 设置标签行内属性
• removeAttribute(name) 移除标签行内属性
与element.属性的区别 上述三个方法用于获取任意的行内属性,包括自定义的属性。
自定义的属性是不能打点调用的:
var box = document.getElementById("box");
// 只能用于元素自有属性
console.log(box.id);
console.log(age.id);
console.log(sex.id);
// 元素自定义的新属性不能用点语法直接调用
// 可以调用元素对象的获取自定义属性的方法
console.log(box.getAttribute("age"));
console.log(box.getAttribute("sex"));
// 也可以调用自有的属性
console.log(box.getAttribute("id"));
// 设置属性,添加新的自定义属性或者自有属性
box.setAttribute("age","20");
box.setAttribute("city","Beijing");
// 传的参数不需要进行属性名的修改
box.setAttribute("class","demo");
// 移除属性
box.removeAttribute("age");
box.removeAttribute("class");
style 样式属性操作
• 使用 style 属性方式设置的样式显示在标签行内。
• element.style 属性的值,是所有行内样式组成的一个样式对象。元素对象的 style 属性的值是一个行内样式组成对象,对象内部封装了所有的行内的样式属性及属性值.
• 样式对象可以继续点语法调用或更改 css 的行内样式属性,例如 width、height 等属性。
注意:
-
类似 background-color 这种复合属性的单一属性写法,是由多个单词组成的,要改为驼峰命名方式书写 backgroundColor。
-
通过样式属性设置宽高、位置的属性类型是字符串,需要加上 px 等单位
<body>
<input type="button" value="按钮" id="btn">
<div id="box" style="width: 100px" class="bg">文字</div>
<script>
.....
// 元素的样式属性对象可以继续打点调用,获取或设置相关的行内样式属性
console.log(box.style);
console.log(box.style.width);
// 注意:如果使用的 css 属性名是复合属性的单一属性,需要更改为驼峰命名法
console.log(box.style.backgroundColor);
box.style.width = "200px"; //会层叠掉前面的样式
</script>
</body>
className 类名属性操作
• 修改元素的 className 属性相当于直接修改标签的类名。
• 如果需要修改多条 css 样式,可以提前将修改后的样式设置到一个类选择器中,后续通过
修改类名的方式,批量修改 css 样式。
<!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>Document</title>
<style>
.cls {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
<script src="common.js"></script>
</head>
<body>
<input type="button" value="按钮" id="btn">
<div id="box">文字</div>
<script>
// 问题:实际工作中我们应该选择哪种方法?
// 获取元素
var btn = my$("btn");
var box = my$("box");
// 给按钮添加事件
btn.onclick = function () {
// 1.通过更改类名
// box.className = "cls";
// 2.通过元素对象的 style 属性进行设置
box.style.width = "100px";
box.style.height = "200px";
box.style.backgroundColor = "yellow";
};
</script>
</body>
</html>
DOM 节点操作
createElement 创建新节点
children 获取节点内部的子元素节点, 只取父子关系的
document.body.appendChild 给 body 添加一个新的节点子元素
document.body.removeChild 移除一个节点子元素
<body>
<div id="box">div 1</div>
<div id="demo">
<p>paragraph 1</p>
<p>paragraph 2</p>
<p>paragraph 3</p>
<div class="inner">
<p>inner p</p>
</div>
</div>
<script>
// 生成一个新的元素对象
var newNode = document.createElement("div");
newNode.innerHTML = "新的 div";
// 给 body 添加一个新的节点子元素 (添加到最后位置)
document.body.appendChild(newNode);
// 移除一些元素
var box = document.getElementById("box");
document.body.removeChild(box);
// 获取节点内部的子元素节点, 只取父子关系的
var demo = document.getElementById("demo");
var child1 = demo.children;
console.log(child1);
</script>
</body>
child1:
节点属性
• nodeType 节点的类型,属性值为数字,表示不同的节点类型,共 12 种,只读
1 元素节点
2 属性节点
3 文本节点
•nodeName 节点的名称(标签名称),只读
• nodeValue 节点值,返回或设置当前节点的值. 元素节点的 nodeValue 始终是 null
父子节点常用属性
• childNodes
只读属性,获取一个节点所有子节点的实时的集合,集合是动态变化的。
• children 常用
只读属性,返回一个节点所有的子元素节点(只有父子关系)集合,是一个动态更新的 HTML 元素集合。
• firstChild
只读属性,返回该节点的第一个子节点,如果该节点没有子节点则返回 null。
• lastChild
只读属性,返回该节点的最后一个子节点,如果该节点没有子节点则返回 null。
• parentNode
返回一个当前节点的父节点,如果没有这样的节点,比如说像这个节点是树结构的顶端或者没有插入一棵树中,这个属性返回 null。
• parentElement
返回当前节点的父元素节点,如果该元素没有父节点,或者父节点不是一个 DOM元素,则返回 null。
<body>
<div id="box">
<p>段落</p>
<span>span 小盒子</span>
</div>
<script>
var box = document.getElementById("box");
// 获取子节点
console.log(box.childNodes); //或获取所有类型的子节点
console.log(box.children); //或获取所有元素类型的子节点(范围更小)
console.log(box.firstChild); //或获取所有类型的子节点的第一个
console.log(box.firstElementChild); //或获取所有元素类型的子节点的第一个
console.log(box.lastChild); //或获取所有类型的子节点的最后一个
console.log(box.lastElementChild); //或获取所有元素类型的子节点的最后一个
// 获取父级
console.log(box.parentNode);
console.log(box.parentElement);
</script>
</body>
兄弟节点常用属性
• nextSibling
只读属性,返回与该节点同级的下一个节点,如果没有返回null。
• previousSibling
只读属性,返回与该节点同级的上一个节点,如果没有返回null。
• nextElementSibling
只读属性,返回与该节点同级的下一个元素节点,如果没有返回null。
• previousElementSibling
只读属性,返回与该节点同级的上一个元素节点,如果没有返回null。
注意:nextElementSibling 和 previousElementSibling 有兼容性问题,IE9以后才支持。
<body>
<div id="box">
<p>这是段落1</p>
<p>这是段落2</p>
<p id="p3">这是段落3</p>
<p>这是段落4</p>
<p>这是段落5</p>
</div>
<script>
// 获取元素
var p3 = document.getElementById("p3");
// 上一个兄弟节点
console.log(p3.previousSibling);
// 下一个兄弟节点
console.log(p3.nextSibling);
// 上一个兄弟元素的节点
console.log(p3.previousElementSibling);
// 下一个兄弟元素的节点
console.log(p3.nextElementSibling);
</script>
</body>
创建新节点的方法
• document.createElement("div")
创建元素节点
• document.createAttribute("id")
创建属性节点
• document.createTextNode("hello")
创建文本节点
一般将创建的新节点存在变量中,方便使用。创建的节点是存储在内存中的, 并没有加载到 dom 树上.
节点常用操作方法
节点常用操作方法 1
• parentNode.appendChild(child)
将一个节点添加到指定父节点的子节点列表末尾。
<body>
<div id="box">
<p>段落内容 1</p>
<p id="p2">段落内容 2</p>
<p>段落内容 3</p>
<p>段落内容 4</p>
</div>
<script src="common.js"></script>
<script>
// 创建新的节点
var div = document.createElement("div");
var cls = document.createAttribute("class");
var txt = document.createTextNode("hello");
// 创建的新的节点,是存储在内存中的,但是并没添加到 DOM 树上
// 获取元素
var box = my$("box");
var p2 = my$("p2");
box.appendChild(div);
// 文本节点也可以添加到元素内部
div.appendChild(txt);
// 注意:自己创建的元素节点本身也是一个对象,也可以去添加一些新的属性和方法,这些操作将来在元素加载到 DOM 树中时,依旧保留
// DOM 中原有的节点也可以传给 appendChild 的参数
// 相当于删除了原来的, 又重新添加了一个元素, 会出现在页面的最后
box.appendChild(p2);
</script>
</body>
• parentNode.replaceChild(newChild, oldChild)
用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点。
// 替换节点
box.replaceChild(div,p2);
• parentNode.insertBefore(newNode, referenceNode)
在参考节点之前插入一个拥有指定父节点的子节点,referenceNode 必须设置,如果 referenceElement 为 null 则 newNode将被插入到子节点的末尾。(也就是说在referenceNode之前添加一个节点, 如果referenceNode为null, 则添加的节点会出现在页面最后)
// 在某个指定子节点之前添加一个新的子节点
box.insertBefore(div,p2);
// 在某个指定子节点之前添加一个新的子节点
box.insertBefore(div,null);
• parentNode.removeChild(child)
移除当前节点的一个子节点。这个子节点必须存在于当前节点中。
// 移除节点
box.removeChild(p2);
节点常用操作方法 2
• Node.cloneNode():克隆一个节点,并且可以选择是否克隆这个节点下的所有内容。参数为 Boolean 布尔值:
- 如果为 true, 表示采用深度克隆, 则该节点的所有后代节点也都会被克隆;
- 如果为 false, 表示采用浅度克隆, 只克隆该节点本身,节点下的内容不会被克隆。 注意: 一定要设置true或false, 因为前期默认true, 后期又默认false, 为了避免麻烦, 最后写好true还是false
注意:克隆时,标签上的属性和属性值也会被复制,写在标签行内的绑定事件可以被复制,但是通过 JavaScript 动态绑定的事件不会被复制。
浅度克隆:
<body>
<div id="box">
<p>段落内容 1</p>
<p id="p2">段落内容 2</p>
<p>段落内容 3</p>
<p>段落内容 4</p>
</div>
<script src="common.js"></script>
<script>
// 获取元素
......
// 克隆元素 box
// 浅度克隆
var newBox = box.cloneNode(false);
document.body.appendChild(newBox);
</script>
</body>
深度克隆: 可以给新克隆的元素一个id, 避免与原来的元素一致.
// 深度克隆
var newBox = box.cloneNode(true);
newBox.id = "newBox";
document.body.appendChild(newBox);
节点常用操作方法 3
• Node.hasChildNodes():没有参数,返回一个 Boolean 布尔值,来表示该元素是否包含有子节点, 不区分节点类型, 即便是只有一个回车也会返回true。
• Node.contains(child):返回一个 Boolean 布尔值,来表示传入的节点是否为该节点的后代节点。(并不只是局限于父子关系)
<body>
<div id="box">
<p>段落内容 1</p>
<div>
<p id="p2">段落内容 2</p>
</div>
<p>段落内容 3</p>
<p>段落内容 4</p>
</div>
<div id="demo">
</div>
<script src="common.js"></script>
<script>
// 获取元素
......
// 判断有没有子节点,不区分节点类型
console.log(box.hasChildNodes());
console.log(demo.hasChildNodes());
// 判断节点内部是否有某个后代节点
console.log(box.contains(p2));
</script>
</body>
可以看到 <div id="demo">
中只有一个回车, 并没有任何元素, 但结果仍然返回了true
判断当前节点是否有子节点的方法总结
有三种方法可以判断当前节点是否有子节点。
• node.firstChild !== null
• node.childNodes.length > 0
• node.hasChildNodes()
<body>
<div id="box">
<p>段落内容 1</p>
<div>
<p id="p2">段落内容 2</p>
</div>
<p>段落内容 3</p>
<p>段落内容 4</p>
</div>
<div id="demo">
</div>
<script src="common.js"></script>
<script>
// 获取元素
var box = my$("box");
var p2 = my$("p2");
var demo = my$("demo");
// 判断内部有子节点的方法有三种
// 1.判断有没有子节点,不区分节点类型
// console.log(box.hasChildNodes());
// console.log(demo.hasChildNodes());
// 2.判断节点内部第一个子节点是否不为空
console.log(box.firstChild !== null);
console.log(demo.firstChild !== null);
// 3.判断子节点的数组对象的长度是否为0
console.log(box.childNodes.length > 0);
console.log(demo.childNodes.length > 0);
// 补充子元素节点是否存在
console.log(box.children.length > 0);
console.log(demo.children.length > 0);
// 判断节点内部是否有某个后代节点
// console.log(box.contains(p2));
</script>
</body>
注意一下 childNodes.length
和 children.length
的区别.