Dom & Bom API
DOM
- DOM是处理HTML或者XML的标准接口
- 在前面的js中,
<script></script>
标签是现在head里的,但是这里的DOM,得先有标签,所以<script></script>
写在<body>
里
获取元素
通过ID获取
document.getElementById()
document.getElementById(‘time’)
返回的是一个元素对象
通过标签名获取
document.getElementsByTagName()
<script>
var lis = document.getElementsByTagName('li');
console.log(lis[0]);
</script>
- 返回的是 获取过来元素对象的集合 以伪数组的形式存储;
- 即使只有一个li,返回的还是伪数组的形式;
- 如果一个li也没有,返回的是空的伪数组;
element.getElementsByTagName('标签名');
//父元素必须是单个对象(必须指明是哪一个元素对象),获取的时候不包括父元素自己
4. 可以先对父元素,指定一个ID,然后var ol = document.getElementById('ol');
5. 然后再用ol.getElementsByTagName('li');
通过HTML5新增的方法获取
document.getElementsByClassName(‘类名’);
document.querySelector(‘选择器’);
根据指定选择器返回第一个元素对象,不用再区分ID,类,…了
里面的选择器需要加符号
document.querySelectorAll(‘选择器’);
var firstBox = document.querySelector('.box');
var firstBox = document.querySelector('#box');
var firstLi = document.querySelector('li');
特殊元素获取
document.body
document.documentElement
事件
事件三要素
- 事件源
var btn = document.getElementById('btn');
- 事件类型 (onclick?,)
- 事件处理程序
btn.onclick = function(){
alert('点秋香')
}
操作元素
修改元素内容
- element.innerText——非标准 (从起始位置到终止位置的内容,但它去除html标签(不识别html标签,里面的标签会直接显示)和空格和换行)
- element.innerHTML——W3C推荐 (从起始位置到终止位置的内容,但它包括html标签,同时保留空格和换行)
<img src="./1.jpg" style="width: 100px;height: 100px;">
<p>早上好</p>
<script>
//获取元素
var img = document.querySelector('img');
var p = document.querySelector('p');
//得到当前的时间
var nowTime = new Date();
var h = nowTime.getHours();
// console.log(h)
if (h < 12) {
img.src = "./1.jpg";
p.innerHTML = '早上好'
} else if (h < 18) {
img.src = "./2.jpg";
p.innerHTML = '下午好'
}else{
}
</script>
修改表单属性
利用DOM可以操作如下表单元素的属性:
type, value, checked, selected, disabled
- 表单里面的值通过修改value值来修改的
样式属性操作
- element.style— 行内样式操作
- element.className— 类名样式操作
.change{
width:30px;
height:30px;
background-color:black;
}
//让当前元素的类名改为了change
//className 会直接更改元素的类名,会覆盖原先的类名
this.className = 'change';
this.className = 'previous change';//这样就是将原先的类和现在的类进行合并啦
//1.获取元素
var div = document.querySelector('div');
//2.注册事件,处理程序
div.onclick = function(){
//div.style里面的属性,采取驼峰命名法,遇到_需要变成大写
//js 修改 style样式操作,产生的是行内样式,css权重比较高
this.style.backgroundColor = 'purple';
}
二维码案例,注意两种获取元素的区别,有的是需要加[0]的
<div class="box">
<img src="./1.jpg" style="width: 200px;height: 200px;" />
<div class="close">X</div>
</div>
<script>
var clo = document.getElementsByClassName('close');
// var clo = document.querySelector('.close');
var pic = document.getElementsByTagName('img');
// var pic = document.querySelector('img');
clo[0].onclick = function () {
pic[0].style.display = 'none';
}
</script>
循环精灵图 backgroundPosition 位置为负值
<!-- 循环精灵图 -->
<style>
ul li {
background-image: url(./sprite.png);
background-repeat: no-repeat;
}
</style>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<script>
lis = document.querySelectorAll('li');
console.log(lis)
// var y;
for (var i = 0; i < lis.length; i++) {
var index = 44 * i;
lis[i].style.backgroundPosition = '0 -' + index + 'px';
}
</script>
显示隐藏文本框内容
<!-- 显示隐藏文本框内容 -->
<input type="text" value="签字笔" style="width: 300px; height:30px; outline: none; color: pink;">
<script>
var inp = document.querySelector('input');
inp.onfocus = function () {
if (this.value == '签字笔') {
this.value = '';
this.style.color = 'black'
}
}
inp.onblur = function () {
if (this.value == '') {
this.value = '签字笔'
this.style.color = 'pink'
}
}
</script>
修改元素小结
排他思想
百度换肤效果
- 得到ul里面的img,可以先用一个querySelector再.querySelectorAll(必须是这种query才可以连用)
表单全选取消全选
<!-- 表单全选取消全选 -->
<table>
<thead>
<td><input type="checkbox" id="j_cbAll"></td>
<td>商品</td>
<td>价钱</td>
</thead>
<tbody id="j_tb">
<tr>
<td><input type="checkbox"></td>
<td>iPhone6</td>
<td>1000</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>2</td>
<td>100</td>
</tr>
</tbody>
</table>
<script>
var j_cbAll = document.getElementById('j_cbAll');
var tds = document.getElementById('j_tb').querySelectorAll('input');
j_cbAll.onclick = function () {
for (var i = 0; i < tds.length; i++) {
tds[i].checked = this.checked;
}
}
//2. 下面复选框需要全部选中
for (var i = 0; i < tds.length; i++) {
tds[i].onclick = function () {
var flag = true;
//每次点击都要检查下面的4个按钮是否全被选中
for (var j = 0; j < tds.length; j++) {
if (!tds[j].checked) {
flag = false;
break; //退出for循环,这样可以提高执行效率,只要有一个没选中,就可以为false了
}
}
j_cbAll.checked = flag;
}
}
</script>
获取自定义属性值
var div = document.querySelector('div')
1.获取元素的属性值
//(1) element.属性-内置的属性
console.log(div.id)
//(2) element.getAttribute('属性')-自定义属性
<div index = '1'></div> index就是程序员自定义的属性
console.log(div.getAttribute('id'));
2.设置属性值
element.属性 = '值' //设置内置属性值
element.setAttribute('属性','值'); //主要针对于自定义属性
3. 移除属性
element.removeAttribute('属性');
tab栏切换
<!-- tab栏切换布局分析 -->
<div class="tab">
<div class="nav">
<ul>
<li class="current">商品介绍</li>
<li>规格与保证</li>
<li>售后保障</li>
<li>商品评价</li>
<li>手机社区</li>
</ul>
</div>
<div class="content">
<div class="item visit">商品介绍模块内容</div>
<div class="item ">规格与保证内容</div>
<div class="item">售后保障内容</div>
<div class="item ">商品评价内容</div>
<div class="item ">手机社区内容</div>
</div>
</div>
<script>
lis = document.querySelector('.nav').querySelectorAll('li');
divs = document.querySelector('.content').querySelectorAll('div');
items = document.querySelectorAll('.item');
for (var i = 0; i < lis.length; i++) {
// 开始给5个小li,设置索引号
lis[i].setAttribute('index', i);
lis[i].onclick = function () {
for (var i = 0; i < lis.length; i++) {
lis[i].className = ''
}
this.className = 'current'
// 内容显示模块
var index = this.getAttribute('index');
// 隐藏所有其他的内容
for (var i = 0; i < items.length; i++) {
items[i].style.display = 'none'
}
items[index].style.display = 'block'
}
}
</script>
节点操作
获取节点
节点至少有三个基本属性
- nodeType
1.1 元素节点,nodeType为1
1.2 属性节点,nodeType为2
1.3 文本节点,nodeType为3(文本节点包含文字、空格、换行等) - nodeName
- nodeValue
//离元素最近的父级节点,如果找不到,返回null
4. parentNode
for (var i = 0; i < as.length; i++) {
as[i].onclick = function () {
// var parent = as[i].parentNode 这样写会报错,要用this
var parent = this.parentNode
lis.removeChild(parent)
}
}
//返回指定节点的子节点的集合(包含元素,属性,文本节点(换行等))
5. parentNode.childNodes
//返回所有的子元素节点,只返回子元素节点,其他节点不返回(重点)
7. parentNode.children
//包含所有的节点
8. parentNode.firstChild
9. parentNode.lastChild
//只返回元素节点,IE9以上才支持
10. parentNode.firstElementChild
10.parentNode.lastElementChild
//实际开发中的写法
11.parentNode.children[0]
12.parentNode.children[parentNode.children.length-1]
新浪下拉菜单
<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>
</ul>
<script>
// <!-- 获取元素 -->
//1.所有的标签
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>
兄弟节点
//包含元素节点或者文本节点等等
1.node.nextSibling
//包含元素节点或者文本节点等等
2.node.previousSibling
//包含元素节点(IE9以上才支持)
3.node.nextElementSibling
//包含元素节点(IE9以上才支持)
4.node.previousElementSibling
创建节点
1. 创建节点
document.createElement('tagName')
因为这些元素原先不存在,是根据需求动态产生的,所有也称为动态创建元素节点
2. 添加节点
2.1 node.appendChild(child)——node父级,child子级
node.appendChild(tr)方法将一个节点添加到指定父节点的子节点列表末尾——类似push
2.2 node.insertBefore(child,指定元素)
3. 页面添加一个新的元素,1.创建元素,2.添加元素
删除节点
1. 删除节点
node.removeChild(child)____删除子节点,并返回删除的节点
复制节点
1. 复制节点(括号里为空或者是false,是浅拷贝,只复制节点,不复制内容)
node.cloneNode()
2. 指定复制的节点放在什么位置
动态生成表格
<!-- 动态生成表格 -->
<table cellspacing="0">
<thead>
<tr><th>姓名</th><th>科目</th><th>成绩</th><th>操作</th></tr>
</thead>
<tbody>
</tbody>
</table>
<script>
//1.学生的数据
var data = [
{
name: '熊阳阳',
subject: 'js',
score: 80
},
{
name: 'conan',
subject: '柯学',
scroe: '100'
},
{
name: 'conan',
subject: '柯学',
scroe: '100'
}
]
//2.根据数组长度,创建行
var tbody = document.querySelector('tbody');
for (var i = 0; i < data.length; i++) {
// 2.1创建行
var tr = document.createElement('tr');
tbody.appendChild(tr)
// 2.2创建单元格,并根据数据填充内容
for (var k in data[i]) {
console.log(data[i].k)
var td = document.createElement('td');
tr.appendChild(td);
td.innerHTML = data[i][k];
}
// 2.3
var td = document.createElement('td');
tr.appendChild(td);
td.innerHTML = '<a>删掉</a>'
}
//3,点击删掉,删掉
var tbody = document.querySelector('tbody');
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function () {
//取出被点击a的父节点(a的父节点是td,td的父节点才是tr)
var del_td = this.parentNode;
//是tbody删掉tr——注意是tbody啦
tbody.removeChild(del_td.parentNode)
}
}
</script>
三种动态创建元素区别
1.document.write()
document.write('<div>123</div>')
直接将内容写入页面的内容流,但是文档流执行完毕,所以会导致页面全部重绘,也就是说,如果页面文档流加载完毕,
再调用这句话会**导致页面重绘**,原来的就没有啦
2.element.innerHTML
element.innerHTML = '<a>我也可以创建标签,啦啦啦</a>'
特点:1. innerHTML 是将内容写入某个DOM节点,**不会导致页面重绘**
2. innerHTML 创建多个元素效率更高(但是要采用数组拼接才效率高)
3.document.createElement()
特点:大量创建时,效率低一点点,但是结构更清晰
DOM 重点核心
获取过来的DOM元素是一个对象,所以称为文档对象模型
注册事件
- 传统方式
btn.onclick = function(){}
特点:注册事件的唯一性
同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
- 方法监听注册方式
1. w3c推荐方式
2. addEventListener()它是一个方法
3. IE9之前的IE不支持此方法,可使用attachEvent()代替
4. 同一个元素同一个事件可以注册多个监听器
5. 按注册顺序依次执行
tips:
type:是字符串,必定加引号,而且不带on(‘click’)
删除事件
var divs = document.querySelectorAll('div');
divs[0].onclick = function(){
alert(11);
divs[0].onclick = null;//传统方式删除事件
}
//2. removeEventListener 删除事件
divs[1].addEventListener('click',fn)
function fn(){
alert(22);
divs[1].removeEventListener('click',fn);
}
DOM事件流
捕获阶段->当前目标阶段->冒泡阶段
tips:第1条,是先捕获再冒泡,但是,在同一时间内,只能处于一个阶段
事件对象
事件发生后,跟事件相关的一系列信息数据的集合都放在这个对象里(event),它有很多属性和方法
绑定事件,触发事件后,比如按下,鼠标移动等等,这些相关的信息就会存在event中,是不需要传进去的
事件对象的常见属性和方法
阻止默认行为
阻止冒泡行为
e.stopPropagation();
e.cancelBubble = true;
son->father->document;如果son添加了阻止事件冒泡,则点击son,father和document不会有反应,但此时,如果点击的是father,但document还是会有反应的
this和e.target的区别
- e.target 返回的是触发事件的对象(元素)
- this 返回的是绑定事件的对象(元素)
ul绑定事件,点击li时,用this则会一直得到ul,用e.target返回的则是li(点击事件对象-即谁被点击啦) - 可能会遇到currentTarget,与this类似,只是也有兼容性问题
事件冒泡带来的应用->事件委托
事件委托的原理
不是每个子节点单独设置监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
以上案例:给ul注册点击事件,然后点击里面的li的时候,当前的li可以用event.target得到,并且点击li,事件会冒泡到ul上
<!-- 事件委托 -->
<ul>
<li>我被点击啦,我变色了</li>
<li>我被点击啦,我变色了</li>
<li>我被点击啦,我变色了</li>
<li>我被点击啦,我变色了</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
for (var i = 0; i < this.children.length; i++) {
this.children[i].style.backgroundColor = ''
}
e.target.style.backgroundColor = 'pink'
})
</script>
常用的鼠标事件
mouseout和mouseleave的区别
因为mouseenter和mouseleave不会冒泡
禁止选中文字和禁止右键菜单
获得鼠标在页面中的坐标
mousedown
clientY:始终是相对于浏览器可视区的,也就是说,当页面向下滑动很多时,向下滑动的总距离不会被包含在clientY里。
pageY:向下滑动的总距离是会被包含在clientY里。
实例:跟随鼠标移动
<!-- 图片跟随鼠标移动 -->
<img src="./1.jpg" style="width: 50px;height: 50px;position: absolute;">
<script>
var pic = document.querySelector('img')
document.addEventListener('mousemove', function (e) {
pic.style.top = e.clientY + 'px';
pic.style.left = e.clientX + 'px';
})
</script>
常用的键盘事件
- onkeypress 不识别功能键,比如左右箭头,ctrl,shift
- 三个事件的执行顺序是:keydown–keypress–keyup
- keyup和keydown事件不区分字母大小写(keyCode)
- keypress是区分大小写的(keyCode)
<!-- 模拟京东按键输入内容案例 -->
<input type="text">
<script>
//监听按下s键
//注意是keyup,不然获取焦点的同时也会写入s
var input = document.querySelector('input');
var inp = document.onkeyup = function (e) {
console.log(e.keyCode)
if (e.keyCode == 83) {
input.value = ''
input.focus()
}
}
</script>
<style>
#large {
width: 200px;
height: 30px;
border: 1px solid rgb(158, 155, 155);
margin-bottom: 10px;
font-style: 18px;
line-height: 30px;
box-shadow: 0 2px 0.5px rgb(158, 155, 155);
}
<!--小箭头-->
#large::before {
content: '';
width: 0;
height: 0;
position: absolute;
top: 31px;
left: 18px;
border: 8px solid black;
border-style: solid dashed dashed;
border-color: white transparent transparent;
}
<!-- 模拟京东快递单号查询 -->
<div style="width: 200px;height: 50px;margin:500px auto">
<div id="all" style="position: relative;display: none;">
<div id="large">
</div>
</div>
<input type="text" style="width: 200px;height: 20px;" placeholder="请输入您的快递单号">
</div>
<script>
var input = document.querySelector('input')
var div = document.querySelector('#large')
var all = document.querySelector('#all')
input.addEventListener('keyup', function (e) {
all.style.display = 'block';
div.innerHTML = this.value
})
input.addEventListener('blur', function () {
all.style.display = 'none';
})
input.addEventListener('focus', function () {
if (this.value != '') {
all.style.display = 'block';
}
})
</script>
</style>
备注
- console.dir(timer);可以看到timer的属性和方法
- this指向的是事件函数的调用者
- 输入的密码,
type="password"
,则显示**,type="text",
显示123 - 多次点击按钮,状态切换
- H5规定自定义属性data开头做为属性名并且赋值,
<div data-index = '1'></div>
<div data-list-name="andy"></div>
//如果自定义属性里面有多个-链接的单词,获取的时候,采用驼峰命名法
console.log(div.dataset.listName);
console.log(div.dataset['listName']);
- 阻止链接跳转需要添加javascript:void(0);或者javascript:;