目录
目录
目标
- 能够说出什么是DOM
- 能够获取页面元素
- 能够给元素注册事件
- 能够操作DOM元素的属性
- 能够创建元素
- 能够操作DOM节点
1、DOM简介
1.1 什么是DOM
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口。
W3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式。
1.2 DOM树
- 文档:一个页面就是一个文档,DOM中使用document表示
- 元素:页面中的所有标签都是元素,DOM中使用element表示
- 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
DOM把以上内容都看做是对象
2、获取元素
2.1 如何获取页面元素
DOM在我们实际开发中主要用来操作元素。
我们如何来获取页面中的元素呢?
获取页面中的元素可以使用以下几种方式:
- 根据ID获取
- 根据标签名获取
- 通过HTML5新增的方式获取
- 特殊元素获取
getElementById()
注意:
- 因为文档页面从上往下加载,所以先有标签,然后才能getElementById
- 参数是字符串,所以需要加引号
- 返回的是一个 element 对象
console.dir 可以打印返回的元素对象,更好的查看里面的属性和方法
getElementsByTagName()
- 参数是字符串,所以需要加引号d
- 得到的是对象的集合,可以用遍历来获取所有对象
- 得到的是动态的 例子: 获取ol里面的li
getElementsByClassName()
类名选择器
querySelector()
HTML5新增的
返回指定选择器的第一个对象
querySelectorAll()
返回指定选择器的所有对象集合 用法和querySelector()一样
document.body
获取body元素
document.documentElement
获取html元素
2.2 根据ID获取
使用getElementById()方法可以获取带有ID的元素对象
Document的方法getElementById( )返回一个匹配特定ID的元素。由于元素的ID在大部分情况下要求是独一无二的,这个方法自然而然地成为了一个高效查找特定元素的方法。
如果需要查找到那些没有ID的元素.你可以考虑过CSS选择器使用querySelector( )。
2.3 根据标签名获取
使用getElementsByTagName()方法可以返回带有指定标签名的对象的集合。
document.getElementsByTagName('标签名');
1.因为得到的是一个对象的集合,所以我们想要操作里面的元素就需要遍历·
2.得到元素对象是动态的
还可以获取某个元素(父元素)内部的所有指定标签名的子元素。
element.getElementsByTagName('标签名');
注意:父元素必须是单个对象(必须指明是哪一个元素对象),获取的时候不包括父元素自己。
<!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>
</head>
<body>
<ul>
<li>知否知否,应是等你好久11</li>
<li>知否知否,应是等你好久11</li>
<li>知否知否,应是等你好久11</li>
<li>知否知否,应是等你好久11</li>
</ul>
<ol id="ol">
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
</ol>
<script>
// 1.返回的是 获取过来元素对象的集合 以伪数组的形式存储的
var lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[0]);
// 2. 我们想要依次打印里面的元素对象我们可以采取遍历的方式
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
// 3. 如果页面中只有一个li 返回的还是伪数组的形式
// 4. 如果页面中没有这个元素 返回的是空的伪数组的形式
// 5. element.getElementsByTagName('标签名'); 父元素必须是指定的单个元素
// var ol = document.getElementsByTagName('ol'); // [ol]
// console.log(ol[0].getElementsByTagName('li'));
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
</script>
</body>
</html>
2.4 通过HTML5新增的方法获取
1. document.getElementsByClassName( 类名'); //根据类名返回元素对象集合
2. document.querySelegtor ( 选择器'); //根据指定选择器返回第一个元素对象
3. document . querySelectorAll( '选择器y); //根据指定选择器返回
<body>
<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav">
<ul>
<li>首页</li>
<li>产品</li>
</ul>
</div>
<script>
// 1. getElementsByClassName 根据类名获得某些元素集合
var boxs = document.getElementsByClassName('box');
console.log(boxs);
// 2. querySelector 返回指定选择器的第一个元素对象 切记 里面的选择器需要加符号 .box #nav
var firstBox = document.querySelector('.box');
console.log(firstBox);
var nav = document.querySelector('#nav');
console.log(nav);
var li = document.querySelector('li');
console.log(li);
// 3. querySelectorAll()返回指定选择器的所有元素对象集合
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li');
console.log(lis);
</script>
</body>
2.5 获取特殊元素(body,html)
获取body元素
1. doucumnet.body //返回body元素对象
获取html元素
1. document .documentElement //返回html元素对象
<!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>
</head>
<body>
<script>
// 1.获取body 元素
var bodyEle = document.body;
console.log(bodyEle);
console.dir(bodyEle);
// 2.获取html 元素
// var htmlEle = document.html;
var htmlEle = document.documentElement;
console.log(htmlEle);
</script>
</body>
</html>
3、事件基础
3.1 事件概述
JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为。
简单理解:触发——响应机制。
网页中的每个元素都可以产生某些可以触发JavaScript的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。
<body>
<button id="btn">唐伯虎</button>
<script>
// 点击一个按钮,弹出对话框
// 1. 事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素
//(1) 事件源 事件被触发的对象 谁 按钮
var btn = document.getElementById('btn');
//(2) 事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
//(3) 事件处理程序 通过一个函数赋值的方式 完成
btn.onclick = function() {
alert('点秋香');
}
</script>
</body>
3.3 执行事件的步骤
1、获取事件源
2、注册事件(绑定事件)
3、添加事件处理程序(采取函数赋值形式)
事件由三部分组成:
- 事件源 事件被触发的对象 比如按钮
- 事件类型 如何触发 比如鼠标点击、鼠标经过、键盘按下、滚动滚轮
- 事件处理程序 通过函数赋值的方式完成
<body>
<div>123</div>
<script>
// 执行事件步骤
// 点击div 控制台输出 我被选中了
// 1. 获取事件源
var div = document.querySelector('div');
// 2.绑定事件 注册事件
// div.onclick
// 3.添加事件处理程序
div.onclick = function() {
console.log('我被选中了');
}
</script>
</body>
事件都有:
鼠标事件 | 触发条件 |
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
3.4 分析事件三要素
下拉菜单三要素
关闭广告三要素
4、操作元素
JavaScript的DOM操作可以改变网页内容、结构和样式,我们可以利用DOM操作元素来改变元素里面的内容、属性等。注意以下都是属性
4.1 改变元素内容
element.innerText
- 从起始位置到终止位置的内容,但它去除Html标签,同时空格和换行也会去掉
- innerText不识别HTML标签
- 可读写的,可以获取元素里面的内容
element.innerHTML
- 从起始位置到终止位置的全部内容,包括Html标签,同时保留空格和换行
- 能识别HTML标签
- 可读写的,可以获取元素里面的内容
<!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>
div,
p {
width: 300px;
height: 30px;
line-height: 30px;
color: #fff;
background-color: pink;
}
</style>
</head>
<body>
<button>显示当前系统时间</button>
<div>某个时间</div>
<p>1123</p>
<script>
// 当我们点击了按钮, div里面的文字会发生变化
// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2.注册事件
btn.onclick = function() {
// div.innerText = '2019-6-6';
div.innerText = getDate();
}
function getDate() {
var date = new Date();
// 我们写一个 2019年 5月 1日 星期三
var year = date.getFullYear();
var month = date.getMonth() + 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>
</body>
</html>
innerText 和 innerHTML的区别
<body>
<div></div>
<p>
我是文字
<span>123</span>
</p>
<script>
// innerText 和 innerHTML的区别
// 1. innerText 不识别html标签 非标准 去除空格和换行
var div = document.querySelector('div');
// div.innerText = '<strong>今天是:</strong> 2019';
// 2. innerHTML 识别html标签 W3C标准 保留空格和换行的
div.innerHTML = '<strong>今天是:</strong> 2019';
// 这两个属性是可读写的 可以获取元素里面的内容
var p = document.querySelector('p');
console.log(p.innerText);
console.log(p.innerHTML);
</script>
</body>
4.2 常用元素的属性操作
1. innerText、 innerHTML改变元素内容
2. src、 href
3. id、alt、 title
<!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>
img {
width: 300px;
}
</style>
</head>
<body>
<button id="ldh">刘德华</button>
<button id="zxy">张学友</button> <br>
<img src="images/ldh.jpg" alt="" title="刘德华">
<script>
// 修改元素属性 src
// 1. 获取元素
var ldh = document.getElementById('ldh');
var zxy = document.getElementById('zxy');
var img = document.querySelector('img');
// 2. 注册事件 处理程序
zxy.onclick = function() {
img.src = 'images/zxy.jpg';
img.title = '张学友思密达';
}
ldh.onclick = function() {
img.src = 'images/ldh.jpg';
img.title = '刘德华';
}
</script>
</body>
</html>
案例:分时显示不同图片,显示不同问候语
根据不同时间,页面显示不同图片,同时显示不同的问候语。
如果上午时间打开页面,显示上午好,显示上午的图片。
如果下午时间打开页面,显示下午好,显示下午的图片。
如果晚上时间打开页面,显示晚上好,显示晚上的图片。
案例分析:
①根据系统不同时间来判断,所以需要用到日期内置对象
②利用多分支语句来设置不同的图片
③需要一个图片,并且根据时间修改图片,就需要用到操作元素src属性
④需要一个div元素,显示不同问候语,修改元素内容即可
<!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>
img {
width: 300px;
}
</style>
</head>
<body>
<img src="images/s.gif" alt="">
<div>上午好</div>
<script>
// 根据系统不同时间来判断,所以需要用到日期内置对象
// 利用多分支语句来设置不同的图片
// 需要一个图片,并且根据时间修改图片,就需要用到操作元素src属性
// 需要一个div元素,显示不同问候语,修改元素内容即可
// 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 = 'images/s.gif';
div.innerHTML = '亲,上午好,好好写代码';
} else if (h < 18) {
img.src = 'images/x.gif';
div.innerHTML = '亲,下午好,好好写代码';
} else {
img.src = 'images/w.gif';
div.innerHTML = '亲,晚上好,好好写代码';
}
</script>
</body>
</html>
4.3 表单元素的属性操作
利用DOM可以操作如下表单元素的属性:
type. value、checked、 selected、disabled
修改表单属性
disabled 让某个表单被禁用,不能被点击, 用法:
btn.onclick = function () {
btn.disabled = true;
//或者写成下面这种
this.disabled = true;
//this指向的是时间函数的调用者
}
<!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>
</head>
<body>
<button>按钮</button>
<input type="text" 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 指向的是事件函数的调用者 btn
}
</script>
</body>
</html>
仿京东显示密码
仿京东显示密码,点击按钮将密码框显示为文本框,并可以查看密码明文
案例分析:
核心思路︰利用样式的显示和隐藏完成,display.none隐藏元素display.block显示元素
点击按钮,就让这个二维码盒子隐藏起来即可
<!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>
.box {
position: relative;
width: 74px;
height: 88px;
border: 1px solid #ccc;
margin: 100px auto;
font-size: 12px;
text-align: center;
color: #f40;
/* display: block; */
}
.box img {
width: 60px;
margin-top: 5px;
}
.close-btn {
position: absolute;
top: -1px;
left: -16px;
width: 14px;
height: 14px;
border: 1px solid #ccc;
line-height: 14px;
font-family: Arial, Helvetica, sans-serif;
cursor: pointer;
}
</style>
</head>
<body>
<div class="box">
淘宝二维码
<img src="images/tao.png" alt="">
<i class="close-btn">×</i>
</div>
<script>
// 1. 获取元素
var btn = document.querySelector('.close-btn');
var box = document.querySelector('.box');
// 2.注册事件 程序处理
btn.onclick = function() {
box.style.display = 'none';
}
</script>
</body>
</html>
案例:循环精灵图背景
可以利用for循环设置一组元素的精灵图背景
案例分析:
首先精灵图图片排列有规律的
核心思路:利用for循环修改精灵图片的背景位置background-position
剩下的就是考验你的数学功底了
让循环里面的i索引号*44就是每个图片的y坐标
<!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>
* {
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: pink;
margin: 15px;
background: url(images/sprite.png) no-repeat;
}
</style>
</head>
<body>
<div class="box">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<script>
// 1. 获取元素 所有的小li
var lis = document.querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
// 让索引号 乘以 44 就是每个li 的背景y坐标 index就是我们的y坐标
var index = i * 44;
lis[i].style.backgroundPosition = '0 -' + index + 'px';
}
</script>
</body>
</html>
案例:显示隐藏文本框内容
京东搜索框,默认是“手机”两个字,当用户点击搜索框的时候,“手机”两个字消失,当输入文本之后,保持文本内容不变
案例分析:
- 如果获得焦点,判断里面是否是默认文字,如果是默认文字,就清空表单内容
- 如果失去焦点,判断表单是否为空,如果为空,则表单内容改为默认文字
- 获得焦点的时候,把文本框里的文字变黑
- 失去焦点的时候,文本框文字变浅
- 获得焦点 onfocus 失去焦点 onblur
案例分析
- 一个大盒子,里面上下两个小盒子
- 上面的模块,点击某一个之后,这个的背景色是红色,其余的是灰色(排他思想)
- 点击某一个之后,显示这个模块对应的内容,其他的隐藏,这个要写到点击事件里面
- 规律:下面的显示内容和上面的小 li 一一对应
- 核心思路:
- 给上面的tab_list 添加自定义属性,属性号从0开始
- 当点击上面的模块,下面的队形的显示模块开始显示,其他的隐藏
<!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>
* {
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 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>
</html>
4.7 H5自定义属性
自定义属性目的︰是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性获取是通过getAttribute ('属性′〉获取。
但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。
H5给我们新增了自定义属性︰
1.设置H5自定义属性
H5规定自定义属性data-开头做为属性名并且赋值。
比如<div data-index= "1” ></div>
或者使用JS设置
element.setAttribute( 'data-index,2)
但是有些自定义属性容易引以歧义,不容易判断是内置属性还是自定义属性,所以H5给我们新增了自定义属性 H5规定自定义属性以 “data-” 开头
2.获取H5自定义属性
- 兼容性:element.getAttribute('data-index')
- H5新增:element.dataset.index 或者 element.dataset[ 'index' ] ie11才开始支持
<!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>
</head>
<body>
<div getTime="20" data-index="2" data-list-name="andy"></div>
<script>
var div = document.querySelector('div');
// console.log(div.getTime);
console.log(div.getAttribute('getTime'));
div.setAttribute('data-time', 20);
console.log(div.getAttribute('data-index'));
console.log(div.getAttribute('data-list-name'));
// h5新增的获取自定义属性的方法 它只能获取data-开头的
// dataset 是一个集合里面存放了所有以data开头的自定义属性
console.log(div.dataset);
console.log(div.dataset.index);
console.log(div.dataset['index']);
// 如果自定义属性里面有多个-链接的单词,我们获取的时候采取 驼峰命名法
console.log(div.dataset.listName);
console.log(div.dataset['listName']);
</script>
</body>
</html>
5、节点操作
5.1 为什么学节点操作
1、利用DOM提供的方法获取元素 (逻辑性不强,繁琐)
- document.getElementById()
- document.getElementByTagName()
- document.querySelector 等等
2、利用节点层级关系获取元素(简单、符合逻辑)
- 利用父子兄的节点关系获取元素
- 逻辑性强,但是兼容性差
5.2 节点概述
一般的,节点至少由nodeType(节点类型)、 nodeName(节点名称)、 nodeValue(节点值)这三个基本属性。
- 元素节点 nodeType 为1
- 属性节点 nodeType 为2
- 文本节点 nodeType 为3 (文本节点包括文字、空格、换行等等)
在实际开发中,节点操作主要操作的是元素节点。
5.3 节点层级
利用DOM树可以把节点划分为不同的层级关系,最常见的是父子兄层级关系。
父级节点
node.parentNode
注意:得到的离元素最近的父级节点(亲爸爸),如果找不到就返回null
子级节点
parentNode.childNodes (标准)
返回包含指定节点的子节点的集合,该集合为即时更新的集合
注意:返回值里面包含的子节点包含元素节点、文本节点等等
所以用 nodeType 判断,用for循环遍历
如果只想要获得里面的元素节点,则需要专门处理。所以我们一般不提倡使用childNodes
parentNode.children (非标准)
是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回(重点掌握)
得到所有的子元素节点,虽然是非标准的,但是得到了浏览器的支持,所以以后大量使用这个
parentNode.firstChild
返回第一个子节点,找不到返回null,不管是文本节点还是元素节点都能找到
parentNode.firstElementChild
返回第一个子元素节点,找不到返回null,只返回元素节点(IE9以上才支持)
parentNode.lastChild
返回最后一个子节点,找不到返回null,不管是文本节点还是元素节点都能找到
parentNode.lastElementChild
返回最后一个子元素节点,找不到返回null,只返回元素节点(IE9以上才支持)
实际开发中,firstchild和 lastchild包含其他节点,操作不方便,而firstElementchild和lastElementchild又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?
解决方案:
1.如果想要第一个子元素节点,可以使用parentNode.children[0]
案例:新浪下拉菜单
分析:nav导航栏中有ul和li,li下面又有ul和li,第二层ul和li在鼠标移上去的时候才显示
- 导航栏里面的li都要有鼠标经过的效果,所以需要循环注册
- 核心原理:当鼠标经过li 的时候,孩子的ul 和li 显示,当鼠标离开,则隐藏
<!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>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
a {
text-decoration: none;
font-size: 14px;
}
.nav {
margin: 100px;
}
.nav>li {
position: relative;
float: left;
width: 80px;
height: 41px;
text-align: center;
}
.nav li a {
display: block;
width: 100%;
height: 100%;
line-height: 41px;
color: #333;
}
.nav>li>a:hover {
background-color: #eee;
}
.nav ul {
display: none;
position: absolute;
top: 41px;
left: 0;
width: 100%;
border-left: 1px solid #FECC5B;
border-right: 1px solid #FECC5B;
}
.nav ul li {
border-bottom: 1px solid #FECC5B;
}
.nav ul li a:hover {
background-color: #FFF5DA;
}
</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>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<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>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
</ul>
<script>
// 1. 获取元素
var nav = document.querySelector('.nav');
var lis = nav.children; // 得到4个小li
// 2.循环注册事件
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、兄弟节点
node.nextSibling 得到下一个兄弟节点,包括元素节点和文本节点
node.previousSibling 得到上一个兄弟节点,包括元素节点和文本节点
//下面两个方法只有IE9以上才能兼容
node.nextElementSibling 得到下一个兄弟元素节点,只有元素节点
node.previousElementSibling 得到上一个兄弟元素节点,只有元素节点
<!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>
</head>
<body>
<div>我是div</div>
<span>我是span</span>
<script>
var div = document.querySelector('div');
// 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
console.log(div.nextSibling);
console.log(div.previousSibling);
// 2. nextElementSibling 得到下一个兄弟元素节点
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);
</script>
</body>
</html>
5.4 创建节点
document.createElement('tagName')
document.createElement()这个方法创建由tagName指定的 HTML 元素,因为这些元素原先不存在,是根据我们的需求动态生成的,所以也称为动态创建元素节点。
5.4 添加节点
1. node .appendchild(child)
node.appendchild()方法将一个节点添加到指定父节点的子节点列表末尾。类似于css里面的after伪元素。
2. node.insertBefore(child,指定元素)
node.insertBefore ()方法将一个节点添加到父节点的指定子节点前面。类似于css里面的 before伪元素。
<!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>
</head>
<body>
<ul>
<li>123</li>
</ul>
<script>
// 1. 创建节点元素节点
var li = document.createElement('li');
// 2. 添加节点 node.appendChild(child) node 父级 child 是子级 后面追加元素 类似于数组中的push
var ul = document.querySelector('ul');
ul.appendChild(li);
// 3. 添加节点 node.insertBefore(child, 指定元素);
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
// 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
</script>
</body>
</html>
案例:简单版发布留言案例
案例分析:
- 页面组成:一个文本域,一个提交按钮,一个留言板
- 当点击提交按钮的时候,先判断文本域内容是不是空,如果是空,就警告
- 如果不是空,就新建一个li,然后把文本域的内容赋值给li,然后在ul里面的前面添加li
<!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>
* {
margin: 0;
padding: 0;
}
body {
padding: 100px;
}
textarea {
width: 200px;
height: 100px;
border: 1px solid pink;
outline: none;
resize: none;
}
ul {
margin-top: 50px;
}
li {
width: 300px;
padding: 5px;
background-color: rgb(245, 209, 243);
color: red;
font-size: 14px;
margin: 15px 0;
}
</style>
</head>
<body>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul>
</ul>
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 注册事件
btn.onclick = function() {
if (text.value == '') {
alert('您没有输入内容');
return false;
} else {
// console.log(text.value);
// (1) 创建元素
var li = document.createElement('li');
// 先有li 才能赋值
li.innerHTML = text.value;
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
}
}
</script>
</body>
</html>
5.5 删除节点
node.removeChild(child);
node.removeChild()从DOM中删除一个子节点,返回删除的节点
<!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>
</head>
<body>
<button>删除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
<script>
// 1.获取元素
var ul = document.querySelector('ul');
var btn = document.querySelector('button');
// 2. 删除元素 node.removeChild(child)
// ul.removeChild(ul.children[0]);
// 3. 点击按钮依次删除里面的孩子
btn.onclick = function() {
if (ul.children.length == 0) {
this.disabled = true;
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
</body>
</html>
案例:删除留言案例
案例分析:
- 在留言板案例的基础上添加功能
- 当把文本域的内容幅值给 li 的时候,多添加一个删除的链接,
- 循环把所有的链接获取过来,当我们点击一个链接的时候,删除当前链接所在的 li
- 阻止链接跳转需要添加javascript:void(0);或者 javascript:;
<!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>
* {
margin: 0;
padding: 0;
}
body {
padding: 100px;
}
textarea {
width: 200px;
height: 100px;
border: 1px solid pink;
outline: none;
resize: none;
}
ul {
margin-top: 50px;
}
li {
width: 300px;
padding: 5px;
background-color: rgb(245, 209, 243);
color: red;
font-size: 14px;
margin: 15px 0;
}
li a {
float: right;
}
</style>
</head>
<body>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul>
</ul>
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 注册事件
btn.onclick = function() {
if (text.value == '') {
alert('您没有输入内容');
return false;
} else {
// console.log(text.value);
// (1) 创建元素
var li = document.createElement('li');
// 先有li 才能赋值
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
// (3) 删除元素 删除的是当前链接的li 它的父亲
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// node.removeChild(child); 删除的是 li 当前a所在的li this.parentNode;
ul.removeChild(this.parentNode);
}
}
}
}
</script>
</body>
</html>
5.6 复制节点(克隆节点)
node.cloneNode()
node.cloneNode() 方法返回调用该方法的节点的一个副本,也称为克隆节点/拷贝节点
注意:
- 如果括号里面的参数为空或者为false,那么只是浅拷贝,即只复制节点本身,不克隆里面的子节点
- 如果括号里面的参数为true,那么是深拷贝,复制标签并且复制里面的内容
<!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>
</head>
<body>
<ul>
<li>1111</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
// 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
// 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
</script>
</body>
</html>
案例:动态生成表格
案例分析
- 因为里面的学生数据都是动态的,我们需要js动态生成。这里我们模拟数据,自己定义好数据。数据我们采取对象形式存储。
- 所有的数据都是放到tbody里面的行里面。
- 因为行很多,我们需要循环创建多个行(对应多少人)
- 每个行里面又有很多单元格(对应里面的数据),我们还继续使用循环创建多个单元格,并且把数据存入里面(双重for循环)
- 最后一列单元格是删除,需要单独创建单元格。
- 因为里面的学生数据都是动态的,我们需要js动态生成。这里我们模拟数据,自己定义好
- 数据。数据我们采取对象形式存储。
- 所有的数据都是放到tbody里面的行里面。
- 因为行很多,我们需要循环创建多个行(对应多少人)
<!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>
table {
width: 500px;
margin: 100px auto;
border-collapse: collapse;
text-align: center;
}
td,
th {
border: 1px solid #333;
}
thead tr {
height: 40px;
background-color: #ccc;
}
</style>
</head>
<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: 'JavaScript',
score: 100
}, {
name: '弘历',
subject: 'JavaScript',
score: 98
}, {
name: '傅恒',
subject: 'JavaScript',
score: 99
}, {
name: '明玉',
subject: 'JavaScript',
score: 88
}, {
name: '大猪蹄子',
subject: 'JavaScript',
score: 0
}];
// 2. 往tbody 里面创建行: 有几个人(通过数组的长度)我们就创建几行
var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) { // 外面的for循环管行 tr
// 1. 创建 tr行
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 2. 行里面创建单元格(跟数据有关系的3个单元格) td 单元格的数量取决于每个对象里面的属性个数 for循环遍历对象 datas[i]
for (var k in datas[i]) { // 里面的for循环管列 td
// 创建单元格
var td = document.createElement('td');
// 把对象里面的属性值 datas[i][k] 给 td
// console.log(datas[i][k]);
td.innerHTML = datas[i][k];
tr.appendChild(td);
}
// 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)
}
}
// for(var k in obj) {
// k 得到的是属性名
// obj[k] 得到是属性值
// }
</script>
</body>
</html>
5.8 三种动态创建元素区别(面试题)
- document.write()
- 直接将内容写入页面的内容流,但是文档流执行完毕之后,他会导致页面全部重绘
- document.innerHTML()
- 将内容写入某个DOM节点,不会导致页面全部重绘
- 拼接字符串的效率低
- 创建多个元素效率更高,(不要拼接字符串,采取数组形式拼接),结构稍显复杂
- document.createElement()
- 创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML比createElement效率高
<!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>
</head>
<body>
<button>点击</button>
<p>abc</p>
<div class="inner"></div>
<div class="create"></div>
<script>
// window.onload = function() {
// document.write('<div>123</div>');
// }
// 三种创建元素方式区别
// 1. document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘
// var btn = document.querySelector('button');
// btn.onclick = function() {
// document.write('<div>123</div>');
// }
// 2. innerHTML 创建元素
var inner = document.querySelector('.inner');
// for (var i = 0; i <= 100; i++) {
// inner.innerHTML += '<a href="#">百度</a>'
// }
var arr = [];for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
// 3. document.createElement() 创建元素
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
var a = document.createElement('a');
create.appendChild(a);
}
</script>
</body>
</html>
innerHTML拼接效率测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>效率测试</title>
</head>
<body>
</body>
<script>
function fn() {
var d1 = +new Date();
var str = '';
for (var i = 0; i < 1000; i++) {
document.body.innerHTML += '<div style="width:100px; height:2px; border:1px solid blue;"></div>';
}
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
</html>
innerHTML数组效率测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>效率测试</title>
</head>
<body>
</body>
<script>
function fn() {
var d1 = +new Date();
var array = [];
for (var i = 0; i < 1000; i++) {
array.push('<div style="width:100px; height:2px; border:1px solid blue;"></div>');
}
document.body.innerHTML = array.join('');
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
</html>
createElement效率测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>效率测试</title>
</head>
<body>
</body>
<script>
function fn() {
var d1 = +new Date();
for (var i = 0; i < 1000; i++) {
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '2px';
div.style.border = '1px solid red';
document.body.appendChild(div);
}
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
</html>
6.DOM重点核心
文档对象模型(Document Object Model,简称DOM ),是W3C组织推荐的处理可扩展标记语言( HTML或者XML )的标准编程接口。
w3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式.
1.对于JavaScript,为了能够使JavaScript操作HTMlL,JavaScript就有了一套自己的dom编程接口。
2.对于HTML,dom使得html形成一棵dom树.包含文档、元素、节点
我们获取过来的DOM元素是一个对象( object ),所以称为文档对象模型
关于dom操作,我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作。
创建
1. document.write
2. innerHTML
3. createElement
增
- appendChild
- insertBefore
删
- removeChild
改
修改DOM元素的属性,DOM元素的内容、属性、表单的值等
- 修改元素属性:src、href、title等
- 修改普通元素内容:innerHTML、innerText
- 修改表单元素:value、type、disable等
- 修改元素样式:style、className
查
- 主要获取查询dom的元素
- DOM提供的API方法:getElementById、getElementByTagName古老用法不太推荐
- H5提供的新方法:querySelecter、querySelectorAll提倡使用
- 利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling)提倡使用
属性操作
主要针对于自定义属性
- setAttribute : 设置DOM的属性
- getAttribute : 得到DOM的属性
- removeAttribute : 移除属性
事件操作
给元素注册事件,采取事件源.事件类型=事件处理程序
鼠标事件 | 触发条件 |
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |