目录
排他思想
如果有同一组元素,想要某一个元素实现某种样式,需要用到循环的排他思想算法:
1、给所有元素清除样式(干掉其他人)
2、给当前元素设置样式(留下我自己)
3、顺序不能颠倒,首先干掉其他人,再设置自己
完成一个案例:有五个按钮,按下时背景设置为粉红色
<style>
div {
margin: 0 auto;
width: 300px;
}
.bg {
background-color: pink;
}
</style>
<body>
<div>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
</div>
<script>
// 1、获取元素
var btns = document.querySelectorAll('button');
// 2、遍历btn,给每一个btn添加点击事件
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
// (1)先清除他人 把所有按钮的背景颜色去掉
for (var i = 0; i < btns.length; i++) {
btns[i].className = '';
}
// (2)再设置自己 设置当前按钮背景颜色
this.className = 'bg';
}
}
</script>
</body>
案例
百度换肤
<style>
body {
background: url(./images/1.jpg) no-repeat;
}
img {
height: 100px;
margin: 1px;
}
div {
display: flex;
justify-content: center;
margin: 0 auto;
}
</style>
<body>
<div>
<a href="#">
<img src="./images/1.jpg" alt="" />
</a>
<a href="#">
<img src="./images/2.jpg" alt="" />
</a>
<a href="#">
<img src="./images/3.jpg" alt="" />
</a>
<a href="#">
<img src="./images/4.jpg" alt="" />
</a>
</div>
<script>
var imgs = document.getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
imgs[i].onclick = function () {
// 把当前点击的图片的src设置给body
document.body.style.background = 'url(' + this.src + ')';
}
}
</script>
</body>
表格隔行变色
<style>
table {
margin: 0 auto;
font-size: 14px;
}
td {
width: 50px;
height: 25px;
text-align: center;
}
.bg {
background-color: pink;
}
</style>
<body>
<table border="1">
<thead>
<tr>
<td>ID</td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>张三</td>
<td>20</td>
<td>男</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>21</td>
<td>男</td>
</tr>
<tr>
<td>3</td>
<td>王五</td>
<td>20</td>
<td>男</td>
</tr>
</tbody>
</table>
<script>
// 获取元素 获取tbody元素下的tr,因为只有tbody下的tr才需要变色
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>
全选
<style>
table {
margin: 0 auto;
font-size: 14px;
}
td {
width: 50px;
height: 25px;
text-align: center;
}
</style>
<body>
<table border="1">
<thead>
<tr>
<td><input type="checkbox" name="quan" id=""></td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" name="" id=""></td>
<td>张三</td>
<td>20</td>
<td>男</td>
</tr>
<tr>
<td><input type="checkbox" name="" id=""></td>
<td>李四</td>
<td>21</td>
<td>男</td>
</tr>
<tr>
<td><input type="checkbox" name="" id=""></td>
<td>王五</td>
<td>20</td>
<td>男</td>
</tr>
</tbody>
</table>
<script>
/**
* 全选要分为两个部分来做
* 1、当全选按钮勾选时,其余按钮勾选,当不勾选时,其他按钮不勾选
* 2、当3个按钮勾选时,全选按钮勾选。只要有一个按钮不勾选,全选按钮则不勾选
*/
var chk = document.querySelector('input'); // 全选按钮
var chks = document.querySelector('tbody').querySelectorAll('input'); // tbody下按钮集合
// 1、当全选按钮勾选时,其余按钮勾选,当不勾选时,其他按钮不勾选
chk.onclick = function () {
for (var i = 0; i < chks.length; i++) {
chks[i].checked = this.checked;
}
}
for (var i = 0; i < chks.length; i++) {
chks[i].onclick = function () {
// 2、当3个按钮勾选时,全选按钮勾选。只要有一个按钮不勾选,全选按钮则不勾选
var flag = true; // 勾选状态 true勾选 false未勾选
// 检查其余按钮是否选中
for (var i = 0; i < chks.length; i++) {
if (!chks[i].checked) {
// 当有一个按钮未选中时,flag设置为false
flag = false;
break; // 结束循环,这样可以提高代码执行效率
}
}
chk.checked = flag; // 设置全选按钮的状态
}
}
</script>
</body>
自定义属性操作
获取属性
API | 说明 |
element.属性名 | 获取属性值 |
element.getAttribute('属性名'); | 获取属性值 |
两者的区别:
element.属性名 用于获取自带属性(元素本身自带的属性)
element.getAttribute('属性名'); 主要用于获取用户自定义属性(标准),也可以获取内置属性
var box = document.getElementById('box');
console.log(box.id); // 1、box
// getAttribute('属性');获取属性值(内置属性和自定义属性)
console.log(box.index); // 2、undefined 错误获取自定义属性的方式
console.log(box.getAttribute('index')); // 3、0
console.log(box.getAttribute('id')); // 4、使用这种方式也可以获取内置属性
设置属性值
API | 说明 |
element.属性 = ’值‘ | 设置内置属性值 |
element.setAttribute('属性','值'); | 设置属性值(主要用于设置自定义属性) |
var box = document.getElementById('box');
// (1)element.属性 = '值'; 设置内置属性
box.id = 'box333';
box.className = 'class';
// (2)setAttribute('属性','值'); 设置属性值((主要)自定义属性和内置属性)
box.setAttribute('index', 0); // 设置自定义属性
box.setAttribute('class', 'footer');
移出属性
API | 说明 |
removeAttribute('属性'); | 移出属性 |
<div id="box" index="0">盒子</div>
<script>
var box = document.getElementById('box');
// (1)element.removeAttribute('属性'); 移出属性
box.removeAttribute('id'); // 移出内置属性
box.removeAttribute('index'); // 移出自定义属性
</script>
tab选项卡案例
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
.tab {
width: 978px;
margin: 100px auto;
}
.tab_list {
height: 39px;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab_list li {
float: left;
height: 39px;
line-height: 39px;
padding: 0 20px;
text-align: center;
cursor: pointer;
}
.tab_list .current {
background-color: #c81623;
color: #fff;
}
.item_info {
padding: 20px 0 0 20px;
}
.item {
display: none;
}
</style>
</head>
<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 lis = document.querySelector('.tab_list').querySelectorAll('li');
var items = document.querySelector('.tab_con').querySelectorAll('.item');
// 编辑添加点击事件
for (var i = 0; i < lis.length; i++) {
lis[i].setAttribute('index', i); // 给每个li设置自定义属性
lis[i].onclick = function () {
// 干掉其他人 所有li清除类名
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
// 留下我自己 给当前li添加类名
this.className = 'current'
// 干掉其他人 全部item隐藏
for (var i = 0; i < items.length; i++) {
items[i].style.display = 'none';
}
// 定义索引变量
var index = this.getAttribute('index');
// 留下我自己 让对应的item显示
items[index].style.display = 'block';
}
}
</script>
</body>
H5自定义属性
自定义属性的目的:是为了保存并使用数据,有些数据可以保存在页面中而不用保存到数据库中。
自定义属性通过getAttriubte('属性')获取。
但是有些自定义属性会分辨不出是自定义属性还是内置属性。
H5规定自定义属性以data-开头作为属性名并赋值。
<body>
<div id="box" data-index="0" data-index-li="0">盒子</div>
<script>
var box = document.getElementById('box');
// (1)设置自定义属性
box.setAttribute('data-time', 2020);
// (2)获取自定义属性
box.getAttribute('data-index');
// (3)H5新增获取自定义属性的方法(只能获取data-开头的自定义属性) - 这种方式可以省略data-
console.log(box.dataset); // 存放了所有以data-开头的自定义属性
// 1、方式一
box.dataset['index'];
// 2、方式二
console.log(box.dataset.index);
// 如果是由多个单词-连接的自定义属性,获取的时候采用驼峰命名法
console.log(box.dataset['indexLi']);
console.log(box.dataset.indexLi);
</script>
</body>
节点操作
节点概述
网页中所有内容都是节点(标签、属性、文本、注释等等),在DOM中,节点都是用node来表示。
HTML DOM所有节点均可以通过javaScript进行访问,所有HTML元素(节点)均可以被修改,也可以创建或删除。
一般,节点至少拥有三个基本类型:nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)
节点层级
利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。
父级节点
node.parentNode
(1) 返回某节点的父节点,注意是最近的父节点。
(2) 没有指定节点则返回null。
<body>
<div class="container">
<div id="box">
<span></span>
</div>
</div>
<script>
var span = document.querySelector('span');
var div = document.querySelector('.container');
console.log(span.parentNode); // 返回id为box的div
console.log(div.parentNode); // 返回body
/**
* (1) 返回距离最近父节点
* (2) 找不到元素返回null
*/
</script>
</body>
子节点
1、parentNode.childNodes(标准)
返回包含指定节点的集合,该集合为即时更新的集合
注意:包含了所有的子节点,包括元素节点、文本节点
如果想要获取元素节点,则需要专门处理,不提倡使用childNode
2、parentNode.children(非标准)
是一个只读属性,返回所有子元素节点,它只返回子元素节点,其余节点不返回(重点掌握)
虽然children是非标准,但是得到了各个浏览器的支持,可以放心使用
<body>
<div class="container">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<script>
var ul = document.querySelector('ul');
/**
* 父节点.childNodes
* 返回所有子节点(包括元素节点、文本节点等等)集合
* 是个伪数组,可以用索引的方式选中某个节点
*/
console.log(ul.childNodes);
/**
* 父节点.children
* 返回所有子元素节点集合
* 是个伪数组,可以用索引的方式选中某个节点
*/
console.log(ul.children); // 获取所有的子元素节点
console.log(ul.children[0]); // 返回第一个li
console.log(ul.children[0].nodeType); // 查看节点类型 1-元素节点
</script>
</body>
第一个子节点
3、parentNode.firstChild
返回第一个子节点,找不到返回null
最后一个子节点
4、parentNode.lastChild
返回最后一个子节点,找不到返回null
第一个元素节点
5、parentNode.firstElementChild
返回第一个元素节点,找不到返回null,IE9以上支持
最后一个元素节点
6、parentNode.lastElementChild
返回最后一个元素节点,找不到返回null,IE9以上支持
<body>
<div class="container">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<script>
var ul = document.querySelector('ul');
console.log(ul.childNodes);
console.log(ul.firstChild); // 返回第一个子节点,找不到返回null
console.log(ul.lastChild); // 返回最后一个子节点,找不到返回null
// parentNode.firstElementChild和parentNode.lastElementChild有兼容性问题,IE9以上才支持
console.log(ul.firstElementChild); // 返回第一个子元素节点,找不到返回null
console.log(ul.lastElementChild); // 返回最后一个自元素节点,找不到返回null
</script>
</body>
在实际开发中,firstChild和lastChild包含其他节点,firstElementChild和lastElementChild又有兼容性问题,那如何获取第一个和最后一个元素节点呢?
解决方案:
1、想要获取第一个元素节点,使用parentNode.children[0]
2、想要获取最后一个元素节点,使用parentNode.children[parentNode.children.length - 1]
<body>
<div class="container">
<ul>
<li class="first"></li>
<li></li>
<li></li>
<li></li>
<li class="last"></li>
</ul>
</div>
<script>
var ul = document.querySelector('ul');
/**
* 实际开发的写法,没有兼容性问题,也不包含其他子节点
*/
console.log(ul.children[0]); // 第一个元素节点
console.log(ul.children[ul.children.length - 1]); // 最后一个元素节点
</script>
</body>
案例:新浪下拉菜单
<style>
* {
padding: 0;
margin: 0;
}
div {
display: flex;
justify-content: center;
}
a {
display: block;
text-decoration: none;
color: black;
float: left;
height: 30px;
width: 80px;
background-color: #ccc;
font-size: 14px;
line-height: 30px;
text-align: center;
}
span {
display: block;
height: 30px;
width: 80px;
}
a:hover span {
background-color: pink;
color: white;
}
ul {
display: none;
background-color: #999;
list-style-type: none;
}
li:hover {
background-color: #888;
color: white;
}
</style>
<body>
<div class="nav">
<a href="javascript:;">
<span>下拉菜单</span>
<ul>
<li>选项一</li>
<li>选项二</li>
<li>选项三</li>
</ul>
</a>
<a href="javascript:;">
<span>下拉菜单</span>
<ul>
<li>选项一</li>
<li>选项二</li>
<li>选项三</li>
</ul>
</a>
<a href="javascript:;">
<span>下拉菜单</span>
<ul>
<li>选项一</li>
<li>选项二</li>
<li>选项三</li>
</ul>
</a>
<a href="javascript:;">
<span>下拉菜单</span>
<ul>
<li>选项一</li>
<li>选项二</li>
<li>选项三</li>
</ul>
</a>
</div>
<script>
var nav = document.querySelector('.nav'); // 获取.nav元素
var as = nav.children; // 获取.nav元素下的所有子元素节点
// 遍历添加鼠标经过/离开事件
for (var i = 0; i < as.length; i++) {
as[i].onmouseover = function () {
// 鼠标经过时,显示元素下的第二个元素节点ul
this.children[1].style.display = 'block';
}
as[i].onmouseout = function () {
// 鼠标离开时,显示元素下的第二个元素节点ul
this.children[1].style.display = 'none';
}
}
</script>
</body>
兄弟节点
node.nextSibling
返回下一个兄弟节点(包含文本节点、元素节点等等)
node.previousSibling
返回上一个兄弟节点(包含文本节点、元素节点等等)
node.nextElementSibling
返回下一个兄弟元素节点,有兼容性问题
node.previousElementSibling
返回上一个兄弟元素节点,有兼容性问题
<body>
<div class="container">
<span id="span1"></span><span id="span2"></span>
<span id="span3"></span>
</div>
<script>
var span2 = document.querySelector('#span2');
// (1) nextSibling和previousSibling
console.log(span2.nextSibling); // 下一个兄弟节点(包含文本节点、元素节点等等)
console.log(span2.previousSibling); // 下一个兄弟节点(包含文本节点、元素节点等等)
// (2) nextElementSibling和previousElementSibling
console.log(span2.nextElementSibling); // 下一个兄弟元素节点,有兼容性问题
console.log(span2.previousElementSibling); // 上一个元素兄弟节点,有兼容性问题
// (3) 对于返回兄弟元素节点兼容性的解决方案
/**
* 封装一个函数,返回下一个元素节点。
*/
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
console.log(getNextElementSibling(span2));
</script>
</body>
创建节点
document.createElement('tagName')
<script>
// document.createElement('标签名') —— 用于创建HTML元素节点,这些节点本来不存在,是动态创建的,所以也叫动态创建节点
console.log(document.createElement('li'));
</script>
添加节点
node.appendChild( child );
node.insertBefore(child,指定位置);
<body>
<div class="container">
<span id="span"></span>
</div>
<script>
var con = document.querySelector('.container');
// (1) 创建节点:document.createElement('标签名') —— 用于创建HTML元素节点,这些节点本来不存在,是动态创建的,所以也叫动态创建节点
var li = document.createElement('li');
// (2) node.appendChild(child)和node.insertBefore(child,指定元素) —— 添加节点
// node 父节点 child 要添加的节点
con.appendChild(li); // con下的子节点后面追加元素
con.insertBefore(li, con.children[0]); // 在span前面追加元素 con.children[0] 父节点下的子节点的第一个位置
</script>
</body>
案例:简单版发布留言
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
div {
display: flex;
justify-content: center;
}
ul {
width: 250px;
min-height: 200px;
border: 1px solid #000;
list-style-type: none;
padding: 5px;
}
li {
width: 100%;
height: 30px;
line-height: 30px;
background-color: pink;
margin: 2px 0;
color: white;
font-size: 13px;
padding: 0 5px;
}
button {
width: 70px;
height: 30px;
border-radius: 5px;
margin: 90px 10px;
}
textarea {
padding: 5px;
width: 250px;
height: 210px;
}
</style>
<body>
<div>
<textarea name="" id="" placeholder="请输入留言"></textarea><br>
<button>发布</button>
<ul>
留言:
</ul>
</div>
<script>
// 获取按钮 文本域 留言区
var btn = document.querySelector('button');
var ul = document.querySelector('ul');
var text = document.querySelector('textarea')
// 添加点击事件
btn.onclick = function () {
/**
* 判断文本域内容是否为空
* 为空做相关提示
* 不为空正常操作
*/
if (text.value.length != 0) {
// 创建li
var li = document.createElement('li');
// 将文本域输入的文本赋值到li
li.innerHTML = text.value;
// 将li添加到ul下
// ul.appendChild(li); 添加后面
ul.insertBefore(li, ul.children[0]); // 添加到最前面
} else {
text.placeholder = '请输入内容!!!!';
alert('请输入内容!!!!');
}
}
</script>
</body>
添加表格案例
<style>
tr td {
text-align: center;
width: 150px;
height: 25px;
font-size: 14px;
}
tr th {
font-family: 500;
font-size: 15px;
}
div {
margin-left: 600px;
}
</style>
<body>
<div>
<p>请输入姓名:<input type="search" value="" id="uname" /></p>
<p>请输入邮箱:<input type="search"></p>
<button>提交</button>
<table border="1">
<thead>
<tr>
<th>
姓名
</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr>
<td>小黑</td>
<td>xiaohei@qq.com</td>
</tr>
</tbody>
</table>
</div>
<script>
// 获取元素
var btn = document.querySelector('button'); // 按钮
var tbody = document.querySelector('tbody'); // tbody
var uname = document.getElementById('uname'); // 姓名文本框
var email = document.querySelectorAll('input')[1]; // 邮箱文本框
btn.onclick = function () {
// 判断文本框内是否为空,如果为空则return,不执行下面语句
if (uname.value == '' || email.value == '') {
alert('请输入内容');
return
}
// 创建tr,并添加到tbody下
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 创建两个td,并把文本框的值赋到td的innerHTML
var td1 = document.createElement('td');
td1.innerHTML = uname.value;
var td2 = document.createElement('td');
td2.innerHTML = email.value;
// 将两个td添加到tr
tr.appendChild(td1);
tr.appendChild(td2);
}
</script>
</body>
删除节点
node.removeChild()
从node节点删除一个子节点,返回删除的节点
<body>
<div class="container">
<span id="span"></span>
</div>
<script>
var con = document.querySelector('.container');
console.log(con.removeChild(con.children[0])); // 删除第一个子节点
</script>
</body>
复制克隆节点
node.cloneNode()
方法返回调用该方法的节点的一个副本。也称为克隆、拷贝节点
注意:
1、如果括号为空或为false时,则是浅拷贝,只会复制节点本身,不克隆里面的子节点
2、如果括号里为true,则是深拷贝,会复制节点里面的所有子节点
<body>
<div class="container">
<span id="span"></span>
</div>
<script>
var con = document.querySelector('.container');
// var cons = con.cloneNode(); 括号为空或false时,只复制节点本身
var cons = con.cloneNode(true); // 括号为true时,包括子节点也会复制
con.appendChild(cons); // 想要添加在节点上时,需要使用添加节点方法
</script>
</body>
创建元素的三种方式
1、document.write()
2、element.innerHTML
3、document.createElement()
区别:
1、document.write() 是将内容直接写入页面的内容流,但是文档流执行完毕,则他会导致页面全部重绘
2、innerHTML是将内容写入某个DOM节点,不会导致页面重绘
3、innerHTML创建多个元素效率更高(不要拼接字符串,采取数组形式拼接的情况下)
4、document.createElement()创建多个元素效率低一点点,但是结构清晰
总结:不同浏览器下,innerHTML效率要比document.createElement()更高
<body>
<div>盒子</div>
<div>盒子</div>
<div>盒子</div>
<button id="btn">按钮</button>
<script>
var btn = document.getElementById('btn');
// 1、document.write() 会导致页面重绘
btn.onclick = () => {
document.write('<div>小盒子</div>');
}
// 2、innerHTML
// 字符串拼接形式 由于字符串的不可变,会一直在内存开辟新空间,所以效率不高
var box = document.querySelectorAll('div')[0];
for (var i = 0; i <= 10; i++) {
box.innerHTML += '<div>小盒子</div>';
}
// 数组拼接形式(效率高)
var arr = [];
for (var i = 0; i < 100; i++) {
arr.push('<div>盒子</div>');
}
box.innerHTML = arr.join('');
// 3、document.createElement() (效率一般)
for (var i = 0; i < 100; i++) {
var div = document.createElement('div')
div.innerHTML = '<div>盒子3</div>';
box.appendChild(div);
}
</script>
</body>