1. DOM 简介
1.1 什么是 DOM
1.1 DOM 树
DOM 把以上内容都看做是对象
2. 获取元素
2.1 如何获取元素
- 根据 ID 获取
- 根据标签名获取
- 通过 HTML5 新增的方法获取
- 特殊元素获取
2.2 根据 ID 获取
使用 getElementById() 方法可以获取带有 ID 的元素对象
2.3 根据标签名获取
使用 getElementsByTagName() 方法可以返回带有指定标签名的对象的集合
还可以获取某个元素(父元素)内部所有指定标签名的子元素
element.getElementsByTagNmae('标签名');
注意:父元素必须是单个对象(必须指明哪一个元素对象).获取的时候不包括父元素自己
2.4 通过 HTML5 新增的方法获取
1. document.getElementsByClassName('类名');//根据类名返回元素对象集合
//这个包括前几种不需要加 . # 等符号
2. document.querySelector('选择器');//根据指定选择器返回第一个元素对象
//需要加符号
3. document.querySelectorAll('选择器');//根据指定选择器返回所有符合的
2.5 获取特俗元素( body ,html )
获取body元素
1. document.body // 返回body元素对象
2. document.documentElement// 返回html元素对象
3. 事件基础
3.1 事件概述
JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为。
简单理解:触发—响应机制
案例理解
3.2 执行事件的步骤
- 获取事件源
- 注册事件( 绑定事件 )
- 添加事件处理程序(采取函数赋值形式)
案例理解
3.3 常见的鼠标事件
4. 操作元素
JavaScript 的 Dom 操作可以改变网页内容、结构和样式,我们可以利用 Dom 操作元素来改变元素里面的内容、属性等。注意以下都是属性
4.1 改变元素内容
element.innerText // element 是元素
获取内容,也可修改内容,不识别html标签(修改时不运行html代码),完全打印文本,同时原本的空格和换行也会去掉
element.innerHTML
获取内容修改内容,识别html标签(修改时会进行html代码操作),同时保留原本的空格和换行
案例理解
<button>显示当前系统事件</button>
<div>某个时间</div>
<p>1111</p>
<script>
// 当我们点击了按钮, div里面的文字会发生变化
// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2.注册事件
btn.onclick = function(){
div.innerText = getDate();
}
function getDate(){
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1; //索引是 0-11 所以要加1
var dates = date.getDate();
var arr = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
var day = date.getDay();
return '今天是:' + year + '年' + month + '月' + dates + '日 ' + arr[day];
}
// 我们元素可以不用添加事件
var p = document.querySelector('p');
p.innerText = getDate();
</script>
4.2 改变元素内容
1. innerText、innerHTML 改变元素内容
2. src、href
3. id、alt、title
案例理解
4.3 表单元素的属性操作
利用 DOM 可以操作如下表单元素的属性:
type、value、checked、selected、disabled
案例理解
<button>按钮</button>
<input type="text" name="" id="" value="输入内容">
<script>
// 1.获取元素
var btn = document.querySelector('button');
var input = document.querySelector('input');
// 2.注册事件 处理程序
btn.onclick = function(){
// input.innerHTML = '点击了' 这个是普通盒子 比如 div 标签里面的内容
// 表单里面的值 文字内容是通过 value 来修改的
input.value = '被点击了';
// 如果想要某个表单被禁 不能再点击 disabled 我们想要这个按钮 button 禁用
// btn.disabled = true;
this.disabled = true;
// this 指向的是事件函数的调用者
}
</script>
仿京东显示隐藏密码案例
<style>
.box {
position: relative;
width: 400px;
border-bottom: 1px solid #ccc;
margin: 100px auto;
}
.box input {
width: 370px;
height: 30px;
border: 0;
outline: none;
}
.box img {
position: absolute;
top: 4px;
right: 2px;
width: 24px;
}
</style>
</head>
<body>
<div class="box">
<label for="">
<img src="img/eyeclose.png" alt="" id="eye">
</label>
<input type="password" name="" id="pwd">
</div>
<script>
// 1. 获取元素
var eye = document.getElementById('eye');
var pwd = document.getElementById('pwd');
// 2.注册事件 处理程序
var flag = 0;
eye.onclick = function(){
// 点击一次之后 flag 一定要变化
if(flag == 0){
pwd.type = 'text';
eye.src = 'img/eyeopen.png';
flag = 1;
}else{
pwd.type = 'password';
eye.src = 'img/eyeclose.png';
flag = 0;
}
}
</script>
</body>
4.4 样式属性操作
我们可以通过 JS 修改元素的大小、颜色、位置等样式。
1. element.style 行内样式操作
2. element.className 类名样式操作
注意:
- JS 里面的样式采取驼峰命名法 比如 fontSize,backgroundColor
- JS 修改 style 样式操作,产生的是行内样式,css权重比较高
获取和失去焦点案例
<style>
input{
color: #999;
}
</style>
</head>
<body>
<input type="text" name="" id="" value = "手机">
<script>
var text = document.querySelector('input');
// 2. 注册事件 获取焦点事件 onfocus
text.onfocus = function(){
console.log('得到了焦点');
if(this.value === '手机'){
this.value = '';
}
// 获得焦点需要把文本框里面的文字变黑
this.style.color = '#333';
}
// 3. 注册事件 失去焦点事件 onblur
text.onblur = function(){
console.log('失去了焦点');
if(this.value === ''){
this.value = '手机';
}
this.style.color = '#999';
}
</script>
</body>
利用 className 修改样式案例
<style>
div{
width: 100px;
height: 100px;
background-color: pink;
}
.change{
background-color: purple;
color: #fff;
font-size: 25px;
margin-top: 100px;
}
</style>
</head>
<body>
<div class='first'>文本</div>
<script>
// 1. element.style 样式少或功能简单才使用
var text = document.querySelector('div');
text.onclick = function(){
//若想保留原先类名,前面添加即可
this.className = 'first change';
}
</script>
</body>
仿新浪注册页面
<style>
div{
width: 600px;
margin: 100px auto;
}
.message {
display: inline-block;
font-size: 12px;
color: #999;
/* background: url(img/mess.png) no-repeat left center; */
padding-left: 20px;
}
.wrong {
color: red;
background: url(img/wrong.png);
}
.right {
color: green;
background: url(img/right.png);
}
</style>
</head>
<body>
<div class="register">
<input type="password" class="ipt">
<p class="message">请输入6~16位密码</p>
</div>
<script>
// 首先判断的事件是表单失去焦点 onblur
var ipt = document.querySelector('.ipt');
var message = document.querySelector('.message');
ipt.onblur = function(){
//根据表单里面值的长度 ipt.value.length
if(this.value.length < 6 || this.value.length > 16){
console.log('错误');
message.className = 'message wrong'
message.innerHTML = '您需要输入6~16位数字';
}else{
message.className = 'message right'
message.innerHTML = '您输入正确';
}
}
</script>
</body>
4.5 操作元素总结
4.6 排他思想
首先排除其他人,然后才设置自己的样式,这种排除其他人的思想我们称为排他思想。
案例
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
var btns = document.getElementsByTagName('button');
// btns 得到的是伪数组 里面的每一个元素 btns[i]
for(var i = 0; i < btns.length; i++){
btns[i].onclick = function(){
console.log(11);
// (1) 我们先把所有的按钮颜色去掉
for(var i = 0 ;i < btns.length; i++){
btns[i].style.backgroundColor = '';
}
// (2) 然后才让当前的颜色变成pink
this.style.backgroundColor = 'pink';
}
}
</script>
</body>
全选反选案例(重要)
<style>
* {
padding: 0;
margin: 0;
}
.wrap {
width: 300px;
margin: 100px auto 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #c0c0c0;
width: 300px;
}
th,
td {
border: 1px solid #d0d0d0;
color: #404060;
padding: 10px;
}
th {
background-color: #09c;
font: bold 16px "微软雅黑";
color: #fff;
}
td {
font: 14px "微软雅黑";
}
tbody tr {
background-color: #f0f0f0;
}
tbody tr:hover {
cursor: pointer;
background-color: #fafafa;
}
</style>
</head>
<body>
<div class="wrap">
<table>
<thead>
<tr>
<th>
<input type="checkbox" id="j_cbAll" />
</th>
<th>商品</th>
<th>价钱</th>
</tr>
</thead>
<tbody id="j_tb">
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPhone8</td>
<td>8000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPad Pro</td>
<td>5000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPad Air</td>
<td>2000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>Apple Watch</td>
<td>2000</td>
</tr>
</tbody>
</table>
</div>
<script>
// 1. 全选和取消全选做法: 让下面所有复选框的checked属性(选中状态) 跟随 全选按钮即可
// 获取元素
var j_cbAll = document.getElementById('j_cbAll'); // 全选按钮
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input'); // 下面所有的复选框
// 注册事件
j_cbAll.onclick = function() {
// this.checked 它可以得到当前复选框的选中状态如果是true 就是选中,如果是false 就是未选中
console.log(this.checked);
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].checked = this.checked;
}
}
// 2. 下面复选框需要全部选中, 上面全选才能选中做法: 给下面所有复选框绑定点击事件,每次点击,都要循环查看下面所有的复选框是否有没选中的,如果有一个没选中的, 上面全选就不选中。
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].onclick = function() {
// flag 控制全选按钮是否选中
var flag = true;
// 每次点击下面的复选框都要循环检查者4个小按钮是否全被选中
for (var i = 0; i < j_tbs.length; i++) {
if (!j_tbs[i].checked) {
flag = false;
break; // 退出for循环 这样可以提高执行效率 因为只要有一个没有选中,剩下的就无需循环判断了
}
}
j_cbAll.checked = flag;
}
}
</script>
</body>
4.7 自定义属性的操作
1. 获取属性值
- element.属性 获取属性值
- element.getAttribute(’ 属性 ');
区别:
- element.属性 获取内置属性值(元素本身自带的属性 class id 等)
- element.getAttribute(’ 属性 '); 主要获取自定义的属性(标准)我们程序员自定义添加的属性
2. 设置元素属性值
- element.属性 = ‘值’ 设置内置属性值
- element.setAttribute( ‘属性’ ,‘值’ ); 主要针对自定义属性(标准)
3. 移除属性
- element.removeAttribute( ‘属性’ );
tab栏切换案例(重要)
<body>
<div class="tab">
<div class="tab_list">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价(50000)</li>
<li>手机社区</li>
</ul>
</div>
<div class="tab_con">
<div class="item" style="display: block;">
商品介绍模块内容
</div>
<div class="item">
规格与包装模块内容
</div>
<div class="item">
售后保障模块内容
</div>
<div class="item">
商品评价(50000)模块内容
</div>
<div class="item">
手机社区模块内容
</div>
</div>
</div>
<script>
// 获取元素
var tab_list = document.querySelector('.tab_list');
var lis = tab_list.querySelectorAll('li');
var items = document.querySelectorAll('.item');
// for循环绑定点击事件
for (var i = 0; i < lis.length; i++) {
// 开始给5个小li 设置索引号
lis[i].setAttribute('index', i);
lis[i].onclick = function() {
// 1. 上的模块选项卡,点击某一个,当前这一个底色会是红色,其余不变(排他思想) 修改类名的方式
// 干掉所有人 其余的li清除 class 这个类
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
// 留下我自己
this.className = 'current';
// 2. 下面的显示内容模块
var index = this.getAttribute('index');
console.log(index);
// 干掉所有人 让其余的item 这些div 隐藏
for (var i = 0; i < items.length; i++) {
items[i].style.display = 'none';
}
// 留下我自己 让对应的item 显示出来
items[index].style.display = 'block';
}
}
</script>
</body>
4.8 H5自定义属性
自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性获取是通过getAttribute( ‘属性’ ) 获取。
1. 设置H5自定义属性
H5规定自定义属性用data- 开头作为属性名并且赋值。
例如 <div data-index = "1"></div>
2. 获取H5自定义属性
- 兼容性获取
element.getAttribute('data-index');
- H5新增
element.dataset.index
或者element.dataset[ 'index' ]
ie 11才开始支持
5. 节点操作
5.1 为什么学节点操作
获取元素通常用两种方式:
1. 利用 DOM 提供的方法获取元素
document.getElementById();
document.getElementsByTagName();
document.querySelector();
- 特点:逻辑性不强、繁琐
2. 利用节点层次关系获取元素
- 利用父子兄节点关系获取元素
- 特点:逻辑性强,兼容性差
5.2 节点概述
一般地,节点至少拥有 nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)这三个基本属性。
- 元素节点 nodeType 为 1
- 属性节点 nodeType 为 2
- 文本节点 nodeType 为 3(文本节点包含文字、空格、换行等)
5.3 节点层次
利用 DOM 树可以把节点划分为不同的层次关系,常见的是父子兄层次关系。
1. 父级节点
node.parentNode
- parentNode 属性可以返回某节点的父节点,注意是最近的一个父节点
- 如果指定的节点没有父节点则返回 null
2. 子节点
- parentNode.childNodes (标准)
parentNode.childNodes 返回包含指定节点的子节点集合,该集合为即时更新的集合。
注意:返回值里面包含了所有的子节点,包括元素节点,文本节点等。
如果只想要获得里面的元素节点,则需要专门处理。所以我们一般不提倡用childNodes
- parentNode.children (非标准)
parentNode.children
是一个只读元素,返回所有子元素节点。它只返回元素节点,其余节点不返回(需要重点掌握)
- parentNode.firstChild
firstChild 返回第一个子节点,找不到则返回null。同样,也是包含所有的节点。
- parentNode.lastChild
lastChild 返回最后一个子节点,找不到则返回null。同样,也是包含所有的节点。
- parentNode.firstElementChild
firstElementChild 返回第一个子元素节点,找不到则返回null。
- parentNode.lastElementChild
lastElementChild 返回第一个子元素节点,找不到则返回null。
注意:这两个方法有兼容性问题,IE9以上才支持
实际开发中,获取第一个和最后一个子节点使用方法为:
parentNode.children[0]
parentNode.children[parentNode.children.length - 1]
3. 兄弟节点
- node.nextSibling
nextSibling 返回当前元素的下一个兄弟节点,找不到则返回null。同样,也是包含所有节点。
- node.previousSibling
previousSibling 返回当前元素的上一个兄弟节点,找不到则返回null。同样,也是包含所有节点。
- node.nextElementSibling
nextElementSibling 返回当前元素的下一个兄弟元素节点,找不到则返回null。
- node.previousElementSibling
previousElementSibling 返回当前元素上一个兄弟元素节点,找不到则返回null。
注意:这两个方法有兼容性问题,IE9以上才支持
如若想解决兼容性,则可封装一个函数:
5.4 创建节点
document.creatElement( ‘tagName’ );
document.creatElement() 方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。
5.5 添加节点
- node.appendChild(child)
node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。类似于css里面的after 伪元素。
- node.insertBefore(child, 指定元素)
node.insertBefore() 方法将一个节点添加到父节点的指定子节点前面,类似于css 里面的before 伪元素。
简单版发布留言案例
<body>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul>
</ul>
<script>
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
btn.onclick = function(){
if(text.value == ''){
alert('您没有输入内容');
return false;
}else{
// 1.创建元素
var li = document.createElement('li');
// 先有 li 才能赋值
li.innerHTML = text.value;
// 2.添加元素
// ul.appendChild(li);
ul.insertBefore(li,ul.childdren[0]);
}
}
</script>
</body>
5.6 删除节点
node.removeChild(child)
node.removeChild() 方法从 DOM 中删除一个子节点,返回删除的节点。
5.7 复制节点(克隆节点)
node.cloneNode()
node.cloneNode() 方法返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点。
注意:
- 如果括号参数为空或者为false,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点。
- 如果括号参数为true,则是深度拷贝,会复制节点本身以及里面的所有子节点。
动态生成表格案例(重要)
<body>
<table cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
// 1.先准备学生数据
var datas = [{
name: '卫英络',
subject: 'JS',
score: 100
},{
name: '红利',
subject: 'JS',
score: 25
},{
name: '阿玛',
subject: 'JS',
score: 68
},{
name: '李武',
subject: 'JS',
score: 87
}];
// 2.往tbody 里面建行: 有几个人(通过数组的长度)我们就创建几行
var tbody = document.querySelector('tbody');
for(var i = 0; i < datas.length; i++){ //外层循环管 tr 行
// 1. 创建 tr 行
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 2. 行里创建单元格(跟数据有关系的3个单元格) td 单元格数量取决于每个对象里面的属性个数 for循环遍历
for(var k in datas[i]){ // 里层循环管 td 列
// 创建单元格
var td = document.createElement('td');
// 把对象里面的属性值 datas[i][k] 给 td
tr.appendChild(td);
td.innerHTML = datas[i][k];
}
// 3. 创建有删除2个字的单元格
var td = document.createElement('td');
td.innerHTML = '<a href="javascript:;"> 删除 </a>'
tr.appendChild(td);
}
// 4.删除操作 开始
var as = document.querySelectorAll('a');
for(var i = 0; i < as.length; i++){
as[i].onclick = function(){
// 点击a 删除 当前 a 所在的行(链接的爸爸的爸爸) node.removeChild(child)
tbody.removeChild(this.parentNode.parentNode);
}
}
</script>
</body>
5.7 三种动态创建元素区别
- document.write()
- element.innerHTML
- document.createElement()
区别
- document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
- innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
- innerHTML 创建多个元素效率更高(不要拼接字符,采取数组形式拼接),结构稍微复杂
- createElement() 创建多个元素效率稍低一点,但是结构更清晰
总结:不同浏览器下,innerHTML 采取数组情况下效率要比 creatElement 高
6. DOM 重点核心(总结)
关于dom操作,我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作。
6.1 创建
1. document.write
2. innerHTML
3. createElement
6.2 增
1. appendChild
2. insertBefore
6.3 删
1. removeChild
6.4 改
主要修改dom的元素属性,dom元素的内容、属性,比哦但的值等
- 修改元素属性:
src、href、title
等 - 修改普通元素内容:
innerHTML、innerText
- 修改表单元素:
value、type、disabled
等 - 修改元素样式:
style、className
6.5 查
主要获取查询dom的元素
- DOM提供的API方法:
getElementById、getElementsByTagName
古老用法不太推荐 - H5提供的新方法:
querySelector、querySelectorAll
提倡 - 利用节点操作获取元素:
父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling)
提倡
6.6 属性操作
主要针对自定义属性。
1. setAttribute:设置dom的属性值
2. getAttribute:得到dom的属性值
3. removeAttribute:移除属性
6.7 事件操作
给元素注册事件,采取 事件源.事件类型 = 事件触发程序