一、Web APIs 简介
我们前面已经学习完了 JS 的基本语法,但是发现很多常用的网页交互效果依然无法实现,这时候就需要学习 Web APIs 来帮助我们实现网页的交互功能。
API 是为我们程序员提供的一个接口,帮助我们实现某种功能。Web APIs 是浏览器提供的一套操作浏览器功能和页面元素的 API(BOM 和 DOM)。
二、什么是 DOM
DOM 是文档对象模型,是 W3C 组织推荐的处理可扩展标记语言(HTML 或 XML)的标准编程接口。W3C 已经定义了一系列的DOM 接口,通过这些 DOM 接口可以改变网页的内容、结构和样式。
① 文档:一个页面就是一个文档,DOM 中使用 document 表示;
② 元素:页面中的所有标签,DOM 中使用 element 表示;
③ 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示。
DOM 把以上内容都看做是对象!
三、获取元素
DOM 在我们实际开发中主要用来操作元素。获取页面中的元素我们可以使用以下几种方式:
① 根据 ID 获取
使用 getElementById() 方法可以获取带有 ID 的元素对象。
<div id = "age"> 19 </div>
<script>
var ager = document.getElementById('age');
console.log(ager); //<div id = "age"> 19 </div> 完整标签选取出来
console.log(typeof ager); //object
</script>
注意点:
① 因为我们文档页面是从上往下加载的,所以先得有标签,script 写到标签下面;
② get 获得,element 元素,by 通过(驼峰命名法);
③ 参数 id 是严格区分大小写的字符串,必须加引号;
④ 返回的结果是一个元素对象;
⑤ console.dir 打印我们返回的元素对象,更好地查看里面的属性和方法。
② 根据标签名获取
使用 getElementsByTagName() 方法可以返回带有指定标签名的对象集合。
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
<script>
var lis = document.getElementsByTagName('li');
console.log(lis); //[li,li,li,li]
console.log(lis[0]); //<li>111</li>
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
} //循环打印
</script>
注意点:
① 返回的是获取过来的元素对象的集合,是以伪数组的形式存储的;
② 如果想要依次打印里面的元素对象,我们可以采取遍历的方法实现;
③ 得到的元素对象是动态的,标签内容改变获取的结果也跟着改变;
④ 如果页面中只有一个 li,返回的还是伪数组,如果页面中没有该元素,返回的是一个空的伪数组。
当页面中有多个相同的标签时,我们想要有选择地获取某个标签(父元素)内部所有指定标签名的子元素,这个时候可以这样写:element.getElementsByTagName(‘标签名’);
<ol id = "ols">
<li>11</li>
<li>22</li>
<li>33</li>
</ol>
<script>
var ool = document.getElementById('ols'); //通过id值把ols这一个元素获取过来
var lis = ool.getElementsByTagName('li'); //获取指定父元素内的指定子元素
console.log(lis);
</script>
注意父元素必须是单个确切的对象,获取时不包括父元素自己!
③ HTML5 新增方法获取
document.getElementsByClassName('类名'); //根据类名返回元素对象集合
document.querySelector('选择器'); //根据指定选择器返回第一个元素对象
document.querySelectorAll('选择器'); //返回指定选择器内所有元素对象的集合
① 任何选择器都可以,切记里面的选择器要加符号(.box、#box、box);
② 第一种方法里的类名直接写,不需要加符号。
④ 获取 body 和 html 元素
document.body; //获取body元素
document.documentElement; //获取html元素
因为一个页面只有一个 body 和 html,所以直接写就可以了!
四、事件基础
JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。
简单理解:触发响应机制。
1.事件三要素
事件有三部分组成,事件源、事件类型和事件处理程序。
① 事件源,事件被触发的对象(触发谁?比如一个按钮);
② 事件类型,如何触发(什么事件?比如鼠标点击、鼠标经过,还是键盘按下);
③ 事件处理程序,通过一个函数赋值的方式完成。
<!--案例 点击按钮弹出一个对话框-->
<button id = "btn">提交</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function() {
alert('提交成功!');
}
</script>
2.执行事件过程
① 获取事件源;
② 注册事件(绑定事件);
③ 添加事件处理程序(采取函数赋值形式)。
<!--案例 点击div,控制台输出我被选中了-->
<div>123</div>
<script>
var dic = document.querySelector('div'); //获取事件源
div.onclick = function() {
console.log('我被选中了');
} //注册事件并添加事件处理程序
</script>
3.常见的鼠标事件
五、操作元素
JavaScript 的 DOM 操作可以改变网页的内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容、属性等。
1.改变元素内容
element.innerText; //从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉
element.innerHTML; //起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行
下面看一个案例!
<!--案例 点击按钮,div里面的文字会发生变化-->
<button>显示当前系统时间</button>
<div>某个时间</div>
<script>
//获取事件
var btn = document.querySelector('button');
var div = document.querySelector('div');
//也可以不添加事件,获取过来直接操作(打开页面就显示时间 div.innerText = getDate();)
btn.onclick = function() {
div.innerText = getDate();
}
//获取当前时间日期
function getDate() {
var date = new Date();
var year = date.getFullYear();
var month = date.date.getMonth() + 1;
var dates = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var day = date.getDay();
return '今天是:' + year + '年' + month + '月' + dates + '日' + arr[day];
}
</script>
innerText 和 innerHTML 的区别:
① innerText 不识别 HTML 标签,当修改后的内容有 HTML 标签时,innerText 会直接把标签也显示出来,同时去除空格和换行;
② innerHTML 是我们 W3C 推荐的标准方法,可识别 HTML标签,同时保留空格和换行(常用);
③ 这两个属性可修改元素里的内容,同样也可以读取元素内容( console.log(div.innerText); );
2.修改元素属性
2.1 按钮切换图片
<!--案例 点击不同的按钮,切换不同的图片-->
<button id = "pg">苹果</button>
<button id = "xj">香蕉</button>
<img src = "pg.jpg" title = "苹果" alt = ""/>
<script>
//1.获取元素
var pg = document.getElementById('pg');
var xj = document.getElementById('xj');
var img = document.querySelector('img');
//2.注册事件 处理程序
pg.onclick = function() {
img.src = 'pg.jpg';
img.title = '苹果';
}
xj.onclick = function() {
img.src = 'xj.jpg';
img.title = '香蕉';
}
</script>
2.2 分时显示图片
案例分析:
① 根据系统不同时间判断,所以需要用到日期内置对象;
②利用多分支语句来设置不同的图片;
③ 需要一个图片,并且根据时间修改图片,就需要用到操作元素 src 属性;
④ 需要一个 div 元素,显示不同的问候语,然后修改元素内容即可。
<!--案例 根据不同时间显示不同图片,同时显示不同的问候语-->
<img src = "swh.jpg" alt = ""/>
<div>上午好</div>
<script>
//1.获取元素
var img = document.querySelector('img');
var div = document.querySelector('div');
//2.获取当前小时数
var date = new Date();
var h = date.getHours();
//3.判断小时数改变图片和文字信息
if (h < 12) {
img.src = 'swh.jpg';
div.innerHTML = '上午好!';
} else if (h >= 12 && h < 18) {
img.src = 'xwh.jpg';
div.innerHTML = '下午好!';
} else {
img.src = 'wsh.jpg';
div.innerHTML = '晚上好!';
}
</script>
3.修改表单属性
<button>按钮</button>
<input type = "text" value = "输入内容"/>
<script>
var btn = document.querySelector('button');
var input = document.querySelector('input');
btn.onclick = function() {
input.value = '被点击了'; //修改表单文本域中的内容
this.disabled = true; //点击之后按钮被禁用,this指向函数的调用者
}
</script>
① innerHTML 这个是修改普通盒子(如 div)里面的内容,而对于表单元素属性的修改我们一律使用属性名;
② 如果想要一个按钮点击之后被禁用不允许再点击,可以用 disabled 来实现( btn.disabled = true ),实际上我们通常用 this 代替 btn 更简单。
3.1 显示隐藏密码
案例分析:
① 核心思路,点击眼睛按钮,把密码框类型改为文本框就可以看见里面的密码了。
② 一个按钮两种状态,点击一次,切换为文本框,继续点击一次切换为密码框。
③ 算法,利用一个 flag 变量,通过判断 flag 的值,如果是1就切换为文本框,如果为0就变为密码框。
<!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>显示密码测试</title>
<style>
body {
background-color: cadetblue;
}
.box {
position: relative;
width: 240px;
border-bottom: 1px solid #ccc;
margin: 200px auto;
background-color: white;
}
.box input {
width: 210px;
height: 26px;
border: 0;
font-size: 19px;
/* 去掉轮廓边框 */
outline: none;
}
/*通过伪类选择器修改密码框默认提示字体*/
::-webkit-input-placeholder {
color:#ccc;
font-size: 16px;
}
.box img {
position: absolute;
top: 6px;
right: 4px;
width: 25px;
}
</style>
</head>
<body>
<div class="box">
<label for="">
<img src="close.png" id = "eye"/>
</label>
<input type="password" placeholder="请输入密码" id="pwd"/>
</div>
<script>
var eye = document.getElementById('eye');
var pwd = document.getElementById('pwd');
//利用flag实现睁眼闭眼效果的切换
var flag = 0;
eye.onclick = function() {
if (flag == 0) {
pwd.type = 'text';
eye.src = 'open.png';
flag = 1;
}else {
pwd.type = 'password';
eye.src = 'close.png';
flag = 0;
}
}
</script>
</body>
</html>
特别记住,要学会利用 flag 值来合理切换不同情况下的事件!
运行结果:
我把这两个眼睛图片也放这里吧,有需要自行保存!
4.修改样式属性
element.style; //行内样式操作
element.className; //类名样式操作
4.1 行内样式操作
<!--案例 点击盒子,盒子就改变颜色-->
<!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: 200px;
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div></div>
<script>
var div = document.querySelector('div');
div.onclick = function() {
this.style.backgroundColor = 'pink'; //属性采取驼峰命名法
}
</script>
</body>
</html>
注意:
① JS 里的样式属性采取驼峰命名法(比如:fontSize、backgroundColor 等);
② JS 修改 style 样式操作,产生的是行内样式,权重较高。
4.1.1 关闭二维码
案例分析:
① 核心思路:利用样式的显示和隐藏完成,display: none 隐藏元素,display: block 显示元素。
② 点击叉号,就让这个二维码盒子隐藏起来。
<div class = "box">
二维码
<img src = "ewm.jpg" alt = ""/>
<i class = "close-btn">x</i>
</div>
<script>
var btn = document.querySelector('.close-btn');
var box = document.querySelector('.box');
btn.onclick = function() {
box.style.display = 'none';
}
</script>
注意不是删掉,而是隐藏起来了!
4.1.2 循环精灵图
如果使用我们以往的方法添加精灵图,会使得我们的代码量非常大,写起来也很麻烦。那么有没有一种简单的方法,可以一次性添加大量的精灵图呢?当然是有的,我们可以利用 for 循环设置一组元素的精灵图背景。(这里不知道精灵图是什么的,可以看我上一篇文章。)
案例分析:
① 首先精灵图图片的排列是有规律的;
② 核心思路,利用 for 循环修改精灵图片的背景位置(background-position);
③ 让循环里面的 i 索引号 * 44 就是每个图片的 y 坐标(竖着排列两个精灵图的间隔测量出来是44)。
<!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>循环精灵图</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
.box {
width: 250px;
margin: 100px auto;
}
.box li {
float: left;
width: 24px;
height: 24px;
background-color: brown;
margin: 15px;
background: url(图.png) no-repeat;
}
</style>
</head>
<body>
<div class="box">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</div>
<script>
var lis = document.querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
var index = i * 44;
lis[i].style.backgroundPosition = '0 -' + index + 'px';
}
</script>
</body>
</html>
前提是精灵图里面的小图标要竖着排列,保证间隔一致!
4.1.3 隐藏文本框内容
当鼠标点击文本框时,里面的默认文字隐藏,当鼠标离开文本框时,里面的文字显示。
案例分析:
① 首先表单需要两个新事件,获得焦点 onfocus 失去焦点 onblur;
② 如果获得焦点,判断表单里面内容是否为默认文字,如果是默认文字就清空表单内容;
③ 如果失去焦点,判断表单内容是否为空,如果为空则将表单内容修改为默认文字。
<input type = "text" value = "手机"/>
<script>
var text = document.querySelector('input');
//获得焦点事件
text.onfocus = function() {
if (this.value === '手机') {
this.value = '';
}
//获得焦点时需要把文本框里面的文字颜色变黑
this.style.color = '#333';
}
//失去焦点
text.onblur = function() {
if (this.value === '') {
this.value = '手机';
}
//失去焦点时需要把文本框里面的文字颜色变浅
this.style.color = '#999';
}
</script>
4.1.4 排他思想(算法)
案例分析:
① 这里有一组按钮,当我们点击一个按钮的时候,只有该按钮变色,且其它按钮都恢复原色;
② 需要用到循环的排他算法。
③ 所有元素全部清除样式,只给当前元素设置样式。
④ 注意顺序不能颠倒,首先清除他人,然后设置自己。
<!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>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
var btns = document.getElementsByTagName('button');
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
//1.清空所有按钮的样式
for (var i = 0; i < btns.length; i++) {
btns[i].style.backgroundColor = '';
}
//2.再给自己设置样式
this.style.backgroundColor = 'blue';
}
}
</script>
</body>
</html>
4.2 类名样式操作
样式比较少或者功能简单的情况下,我们使用上面的行内样式操作。但是
如果样式比较多的时候,我们还使用这种方法是不是显得很啰嗦呢?没关系,这里我们学习第二种修改样式属性的方法 —— 类名样式操作。
<!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: 400px;
height: 600px;
background-color: blue;
font-size: 30px;
color: black;
margin: 200px 200px;
}
.change {
width: 400px;
height: 400px;
background-color: coral;
margin: auto;
}
</style>
</head>
<body>
<div class = "box">大盒子<div>
<script>
var box = document.querySelector('div');
box.onclick = function() {
if (this.className === 'change') {
this.className = 'box';
}else {
this.className = 'change';
}
}
</script>
</body>
</html>
注意:
① 如果样式修改较多,可以采用操作类名方式更改元素样式;
② class 是个保留字,因此使用 className 来操作元素类名属性;
③ className 会直接更改元素的类名,也就是会直接覆盖掉原先的类名。
但是大多数时候,我们并不需要把原先类里面所有的属性都修改掉,大量重复的样式再写进新的类里面显然是很繁琐的,当然是有办法可以解决的,还记得多类名选择器吗?
this.className = 'first change';
使用多类名选择器,这样我们的新类里面就不需要写那么多本不需变动的样式,只需要将需要改变的样式属性写到新类里面,两个类同时使用即可。
4.2.1 密码框验证信息
案例分析:
① 首先判断的事件是表单失去焦点 onblur。
② 如果输入正确,则提示正确的信息,颜色为绿色,小图标变化。
③ 如果输入位数不是6到16位,则提示错误信息颜色为红色,小图标变化。
④ 因为里面变化样式较多,我们采取 className 修改样式。
<!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>密码框验证</title>
<style>
div {
width: 600px;
margin: 300px auto;
}
.message {
display: inline-block;
font-size: 13px;
color: #999;
background: url(提示.png) no-repeat left center;
background-size:16px 16px;
padding-left: 20px;
}
.wrong {
color: red;
background-image: url(叉号.png);
}
.right {
color: green;
background-image: url(对号.png);
}
</style>
</head>
<body>
<div>
<input type="text" class="ipt"/>
<p class="message">请输入6到16位密码!</p>
</div>
<script>
var ipt = document.querySelector('.ipt');
var message = document.querySelector('.message');
ipt.onblur = function() {
if (this.value.length < 6 || this.value.length > 16) {
message.className = 'message wrong';
message.innerHTML = '您输入的密码位数不满足条件!';
}else {
message.className = 'message right';
message.innerHTML = '密码格式正确!';
}
}
</script>
</body>
</html>
运行结果:
4.2.2 表格隔行变色
案例分析:
① 用到新的鼠标事件,鼠标经过 onmouseover,鼠标离开 onmouseout。
② 核心思路,鼠标经过 tr 行,当前行改变背景颜色,鼠标离开后去掉该背景颜色。
③ 注意第一行 thead 不需要变换颜色,我们要获取的是 tbody 里面的行。
<!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>
table {
width: 800px;
margin: 100px auto;
text-align: center;
/* 合并相邻边 */
border-collapse: collapse;
font-size: 14px;
border: 1px solid aqua;
}
thead tr {
height: 30px;
background-color: aqua;
}
tbody tr {
height: 30px;
}
.bg {
background-color: burlywood;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>代码</th>
<th>名称</th>
<th>累计净值</th>
<th>前单位净值</th>
<th>净值增长率</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<script>
var trs = document.querySelector('tbody').querySelectorAll('tr');
for (var i = 0; i < trs.length;i++) {
trs[i].onmouseover = function() {
this.className = 'bg';
}
trs[i].onmouseout = function() {
this.className = '';
}
}
</script>
</body>
</html>
4.2.3 表单全选取消
案例分析:
① 全选和取消全选做法:让下面所有复选框的 选中状态(checked 属性)跟随全选按钮的选中状态即可。
② 下面复选框只要有一个未选中,全选就取消做法:给下面所有复选框绑定点击事件,每次点击都要循环查看其他的复选框有没有全部都选中,如果发现有一个未选中,上面全选取消。
③ 可以设置一个变量,来控制全选是否选中。
<!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>
table {
width: 800px;
margin: 100px auto;
text-align: center;
border-collapse: collapse;
}
thead tr {
height: 30px;
background-color:rgb(62, 62, 227);
}
tbody tr {
height: 30px;
background-color: antiquewhite;
}
</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>
var j_cbAll = document.getElementById('j_cbAll');
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');
//1.点击全选,下面所有复选框都被选中
j_cbAll.onclick = function() {
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;
for (var i = 0; i < j_tbs.length; i++) {
if (!j_tbs[i].checked) {
flag = false;
//只要发现有一个没被选中结果就已经确定了,后面无需再判断
break;
}
}
j_cbAll.checked = flag;
}
}
</script>
</body>
</html>
运行结果:
5.修改自定义属性
对属性的操作我们有两种方法,第一种是我们前面所学的元素.id
,但是这种方法只能对内置属性进行操作,而我们这里所讲的是另一种方法元素.setAttribute()
,它不仅能对内置属性进行操作,更主要的功能是用来操作自定义的属性。
<div id-"demo" index = "1"></div>
<script>
var div = document.querySelector('div');
//获取元素的属性值
var a = div.id; //demo 第一种方法,只能获取内置属性的值
var b = div.getAttribute('id'); //demo 第二种方法,主要用来获取自定义属性的值
//修改元素的属性值
div.setAttribute('id', 'play');
//移除自定义属性
div.removeAttribute('index');
</script>
5.1 tab 栏切换
重点案例!!
案例分析:
① 当鼠标点击上面相应的选项卡,下面的内容会跟着变化。
② Tab 栏有两大模块,点击上面的某一个选项卡,当前这一底色变为红色,其余不变,你是否想到了用排他思想修改类名?
③ 下面的模块内容,会随着上面的选项卡的变化而变化,所以该变化要写到点击事件里面。
④ 下面的模块显示内容和上面的选项卡是一一对应的,相匹配。
⑤ 核心思路,给上面的 tab_list 里面的所有的 li 添加自定义属性,属性值从0开始编号。
⑥ 点击 tab_list 里面的某个 li,让 tab_con 里面对应序号的内容显示,其余隐藏即可。
<!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>
.tab {
width: 660px;
height: 350px;
margin: 200px auto;
}
.tab_list li {
float: left;
height: 39px;
line-height: 39px;
padding: 0 20px;
text-align: center;
list-style: none;
cursor: pointer;
}
.tab_list .current {
background-color: brown;
color: aliceblue;
}
.tab_con {
font-size: 15px;
padding: 60px 41px;
}
.item {
display: none;
}
</style>
</head>
<body>
<div class="tab">
<div class="tab_list">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价(5000)</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">
商品评价模块内容
</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++) {
//给li设置索引号
lis[i].setAttribute('index', i);
lis[i].onclick = function() {
//1.清除所有li的样式
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
//2.给当前li添加样式
this.className = 'current';
var index = this.getAttribute('index');
for (var i = 0; i < lis.length; i++) {
items[i].style.display = 'none';
}
items[index].style.display = 'block';
}
}
</script>
</body>
</html>
运行结果:
5.2 H5 自定义属性
自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性通过 getAttribute(‘属性’) 获取。但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。H5 给我们新增了自定义属性,H5 规定自定义属性的属性名都以 data- 开头。
比如<div data-index = "1"></div>
,或者使用 JS 设置element.setAttribute('data-index', 2)
。
div.getAttribute('data-index'); //这是我们之前获取自定义属性的方法
div.dataset.index; //这是H5新增的获取自定义属性的方法
div.dataset['index']; //同上
H5 新增方法只有 ie11 以上版本才支持,所以我们一般还是用老方法 getAttribute!
六、节点操作
1.为什么学习节点
获取元素通常使用两种方式:
① 利用 DOM 提供的方法获取(我们前面所学的),缺点就是逻辑性不强,非常繁琐;
② 利用节点层级关系获取,通过父子兄弟节点关系获取元素,相较于上一种方法,它的逻辑性更强,操作简单,但是兼容性较差。
① 网页中所有的内容都是节点,在 DOM 中节点用 node 来表示;
② 一般地,节点至少拥有 nodeType、nodeName 和 nodeValue 这三个基本属性;
③ 元素节点类型为1,属性节点类型为2,文本节点类型为3;
我们实际开发中,节点操作主要操作的是元素节点!
2.节点层级
<ul>
<li><li>
<li><li>
<li><li>
<li><li>
</ul>
<div class="box">
<span class="top"></span>
</div>
<script>
//1.父节点 parentNode返回的是它的父亲(离它最近的父结点)
var top = document.querySelector('.top');
console.log(top.parentNode);
//2.子节点 children返回所有的元素子节点,也是我们实际开发中常用的
var ul = document.querySelector('ul');
console.log(ul.children);
//3.第一个和最后一个子节点 firstChild 和 lastChild
var ul = document.querySelector('ul');
console.log(ul.firstChild); //#text 注意这里返回的是第一个子节点(包括文本节点和元素节点等)
console.log(ul.firstElementChild); //与上面的不同,这个方法返回的直接是第一个元素子节点,但缺点是兼容性差,低版本不支持
console.log(ul.children[0]); //实际开发中的写法,既没有兼容性问题又可以返回第一个子元素
//4.兄弟节点 不常用
var ul = document.querySelector('ul');
console.log(ul.nextSibling); //返回当前元素的下一个兄弟节点,同样也包含文本节点等所有的节点
console.log(ul.previousSibling); //返回当前元素的上一个兄弟节点,同样也包含文本节点等所有的节点
console.log(ul.nextElementSibling); //返回当前元素的下一个兄弟元素节点,有兼容性问题
console.log(ul.previousElementSibling);//返回当前元素的上一个兄弟元素节点
</script>
子节点除了 parentNode.children 外,其实还有另一种方法 parentNode.childNodes,但我们不推荐!
因为它返回的是所有的孩子节点,包括元素节点、文本节点等,想要单独把元素节点显示出来得使用 for 循环来实现,显然太过繁琐。所以我们不使用该方法,但上面的 parentNode.children 是要重点掌握的。
2.1 下拉菜单
① 导航栏里面的 li 都要有鼠标经过效果,所以需要循环注册鼠标事件。
② 核心原理,当鼠标经过, li 里面的 ul 显示,鼠标离开 ul 隐藏。
<!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>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
color: black;
}
.nav {
margin: 60px 500px;
}
.nav>li{
position: relative;
float: left;
height: 41px;
width: 114px;
text-align: center;
background-color: aliceblue;
color: black;
}
.nav>li>a {
display:inline-block;
width: 100%;
height: 100%;
line-height: 41px;
}
.nav>li>a:hover {
background-color:rgb(196, 172, 245);
}
.nav ul {
display: none;
position: absolute;
top: 41px;
left: 0;
width: 100%;
border-left: 1px solid rgb(196, 92, 231);
border-right: 1px solid rgb(196, 92, 231);
}
.nav ul li {
border-bottom: 1px solid rgb(196, 92, 231);
}
.nav ul li a {
display: block;
line-height: 37px;
font-size: 13px;
width: 100%;
height: 100%;
}
.nav ul li a:hover {
background-color: antiquewhite;
}
</style>
</head>
<body>
<ul class="nav">
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="#">私信</a>
</li>
<li>
<a href="#">评论</a>
</li>
<li>
<a href="#">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">博客</a>
<ul>
<li>
<a href="#">博客评论</a>
</li>
<li>
<a href="#">未读提醒</a>
</li>
</ul>
</li>
<li>
<a href="#">邮箱</a>
<ul>
<li>
<a href="#">免费邮箱</a>
</li>
<li>
<a href="#">VIP邮箱</a>
</li>
<li>
<a href="#">企业邮箱</a>
</li>
</ul>
</li>
</ul>
<script>
var nav = document.querySelector('.nav');
var lis = nav.children; //得到4个li
for (var i = 0; i < lis.length; i++) {
lis[i].onmouseover = function() {
this.children[1].style.display = 'block';
}
lis[i].onmouseout = function() {
this.children[1].style.display = 'none';
}
}
</script>
</body>
</html>
运行结果:
3.添加节点
//1.创建节点
document.createElement('tagName');
//2.添加节点 两种方法
node.appendChild(child);
node.insertBefore(child, 指定元素);
① document.createElement() 方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以也称为动态创建元素节点。
② node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。
③ node.insertBefore() 方法可以将一个节点添加到父节点的指定子节点前面。
// 给ul添加li
<ul></ul>
<script>
var li = document.createElement('li'); //创建节点元素li
var ul = document.querySelector('ul');
ul.appendChild(li); //给父级ul添加子级li,末尾追加(常用)
ul.insertBefore(li, ul.children[1]); //将li添加到ul的第二个子节点的前面,索引从0开始
</script>
4.删除节点
node.removeChild(child);
该方法从 DOM 中删除一个子节点,并返回删除的节点。
4.1 发布及删除留言
案例分析:
① 点击按钮之后,就动态创建一个 li,添加到 ul 里面。
② 创建 li 的同时,把文本域里面的值通过 li.innerHTML 赋值给 li。
③ 留言在前面显示用 insertBefore 。
④ 当我们把文本域里面的值赋值给 li 的时候,多添加一个删除的链接。
⑤ 需要把所有的链接获取过来,当我们点击当前的链接的时候,就删除当前链接所在的 li。
⑥ 点击删除链接的时候,地址会发生改变,为了阻止链接跳转,href 里面写javascript:;
即可
<textarea name="" id="">123</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.innerHTML = text.value + "<a href='javascript:;'>删除</a>"; //把文本框中的内容给li,显示出来并添加删除键
//2.添加元素
ul.insertBefore(li, ul.children[0]);
//3.删除元素
var as = document.querySelector('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
ul.removeChild(this.parentNode); //当前链接的父亲就是我们要删除的元素li
}
}
}
}
</script>
5.复制节点
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
var lili = ul.children[0].cloneNode(true); //将第一个li复制上
ul.appendChild(lili); //将复制好的内容追加到原列表后面
</script>
node.cloneNode();
node.cloneNode() 方法返回调用该方法节点的一个副本,也称为克隆节点或拷贝节点。如果括号里面的参数为空或者为 false,则是浅拷贝,即只克隆复制节点本身,并不会克隆里面的内容,只有括号里面为 true 时,才会将标签及标签里面的内容全部复制上。