1. DOM简介
2. 获取元素
(1). 根据标签名获取
1. 根据标签名获取 :使用getElementsByTagName() 方法可以返回带有指定标签名的对象的集合。
document.getElementsTagName('标签名');
注意:
1. 因为得到的是一个对象的集合,所以我们想要操作里面的元素就需要遍历
2. 得到的元素是动态的
2. 还可以获取某个元素(父元素)内部所有指定标签名的子元素。
element.getElementsTagName('标签名');
注意:父元素必须是单个对象(必须指明是哪一个元素对象).获取的时候不包括父元素自己
// 1. 返回的是:获取过来元素对象的集合,以伪数组的形式存储
var lis = document.getElementsTagName('li');
console.log(lis);
console.log(lis[0]);
// 2. 我们想要依次打印里面的元素对象,我们可以采取遍历的方式
for (var i = 0;i < lis.length; i++){
console.log(lis[i]);
}
// 3. 如果页面只有一个li,返回的还是伪数组的形式
// 4. 如果页面中没有这个元素,返回的是空的为数组的形式
// var ol = document.getElementsTagName('ol'); //[ol]
// console.log(ol[0].getElementsTagName('li'));
var ol = document.getElementById('ol');
console.log(ol.getElementsTagName('li'));
(2). 通过HTML5新增的方法获取
1. document.getElementsByClassName('类名'); // 根据类名返回对象集合
2. document.querySelector('选择器'); // 根据指定选择器返回第一个元素对象
3. document.querySelectorAll('选择器'); // 根据指定选择器返回
// 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.Selector('li');
console.log(li);
// 3. querySelectAll() 返回指定选择器的所有元素集合
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li');
console.log(lis);
(3). 获取特殊元素(body, html)
1. 获取body元素
document.body // 返回body元素对象
2. 获取html元素
document.documentElement // 返回html元素对象
3. 事件
(1). 执行事件的步骤
1. 获取事件源
2. 注册事件(绑定事件)
3. 添加事件处理程序(采取函数赋值形式)
// 执行鼠标事件步骤
点击 div 控制台输出:我被选中了
// 1. 获取事件源
var div = document.querySelector('div');
// 2. 绑定事件 注册事件
// div.onclick
// 3. 添加事件处理程序
div.onclick = function() {
console.log('我被选中了');
}
(2). 常见的鼠标事件
// 执行鼠标事件步骤
点击 div 控制台输出:我被选中了
// 1. 获取事件源
var div = document.querySelector('div');
// 2. 绑定事件 注册事件
// div.onclick
// 3. 添加事件处理程序
div.onclick = function() {
console.log('我被选中了');
}
4. 操作元素
(1). 改变元素内容
element.innerText
从起始位置到终止位置的内容,但它取出html标签,同时空格和换行也会去掉
element.innerHTML
起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行
// 当我们点击了按钮,div里面的文字会发生变化
// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2. 注册事件
btn.onclick = function() {
div,innerText = '2019-6-6';
}
// innerText 和 innerHTML 的区别
// 1. innerText 不识别html标签 非标准 去除空格和换行
var div = document.querySelector('div');
// div.innerText = '<strong>今天是:</strong> 2019';
// 2. innerHTNL 识别html 标签 W3C标准,保留空格和换行的
div.innerHTML = '<strong>今天是:</strong> 2019';
// 这两个属性是可读写的,可以获取元素里面的内容
var p = document.querySelector('p');
console.log(p.innerText);
console.log(p.innerHTML);
修改元素属性 src:
<button id = "ldh">刘德华</button>
<button id = "zxy">张学友</button>
<img src="img/ldh.jpg" alt="" title="刘德华">
<script>
// 修改元素属性 src
// 1. 获取元素
var ldh = document.getElementById('#ldh');
var zxy = document.getElementById('#zxy')
var img = document.querySelector('img');
// 2. 注册事件,处理程序
zxy.onclivck = function() {
img.src = 'img/zxy.jpg';
img.title = '张学友';
}
ldh.onclik = function() {
img.src = 'img/ldh.jpg';
img.title = '刘德华';
}
禁用按钮disabled=true;
// 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
}
(2). 样式属性操作(焦点)
我们可以通过js修改元素的大小,颜色,位置等样式。
1. element.style 行内样式操作
2. element.className 类名样式操作
注意:
1. js里面的样式采取驼峰命名法,比如:fontSize, backgroundColor
2. js修改style样式操作,产生的是行内样式,css权重比较高
3. 如果样式修改较多,可以采取类名方式更改元素样式
4. class因为是保留字,因此使用classsName来操作元素类名属性
5. className 会直接更改元素的类名,会覆盖原先的类名。
// 焦点
// 1. 获取元素
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';
}
1. 使用element.style 获得修改元素样式,如果样式较少或者功能简单的情况下使用
2. 通过修改元素的className更改元素的样式,适合于样式较多或者功能复杂的情况
3. 如果想要保留原先的类名,我们可以这么做:多类名选择器
// 1. 使用element.style 获得修改元素样式,如果样式较少或者功能简单的情况下使用
var test = document.querySelector('div');
test.onclick = function() {
this.style.backgroundColor = 'purple';
this.style.color = '#fff';
this.style.fontSize = '25px';
this.style.marginTop = '100px';
// 让我们当前元素的类名改为change
// 2. 通过修改元素的className更改元素的样式,适合于样式较多或者功能复杂的情况
// 3. 如果想要保留原先的类名,我们可以这么做:多类名选择器
// this.className = 'change';
this.className = 'first change';
}
// 1. 获取元素
var ipt = document.querySelector('.ipt');
var message = document.querySelector('.message');
// 2. 注册事件,失去焦点
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.inner = '正确';
}
}
(3). 操作元素总结
(4). 排他思想
百度换肤
// 百度换肤
// 1. 获取元素
var imgs = document.querySelector('.baidu').querySelectorAll('img');
// 2. 循环注册事件
for (var i = 0; i < imgs.length; i++) {
imgs[i].onclick = function() {
// this.src 就是我们点击图片的路径 images/2.jpg
// console.log(this.src)
// 把这个路径this.src 给body就可以了
document.body.style.backgroundImage = 'url(' + this.src + ')';
}
}
勾选框初级
<table border="1">
<thead><td>头</td></thead>
<tbody>
<tr><td>1</td></tr>
<tr><td>2</td></tr>
<tr><td>3</td></tr>
</tbody>
</table>
// 1. 获取元素
var tbody = document.querySelector('tbody').querySelectorAll('tr');
// 2. 循环注册事件
for (var i = 0; i < tbody.length; i++) {
console.log(tbody[i].onmouseover);
tbody[i].onmouseover = function() {
this.className = 'trs';
}
tbody[i].onmouseout = function() {
this.className = '';
}
}
勾选框高级
// 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;
}
}
(5). 自定义属性的操作
1). 获取属性值
element.属性 获得属性值
element.getAttribute('属性');
区别:
element.属性 获得内置属性值(元素本身自带的属性)
element.getAttribute('属性'); 主要获得自定义属性(标准)我们程序员自定义的属性
// <div id = "demo" index = "1"></div>
var div = document.querySelector('div');
// 1. 获取元素的属性值
// (1) element.属性
console.log(div.id);
// (2) element.getAttribute('属性'); get得到获取 attribute属性的意思
// 我们程序员自己添加的属性,我们称为自定义属性 index
console.log(div.getAttribute('id'));
console.log(iv.getAttribute('index'));
// 2. 设置元素属性值
// (1) element.属性 = '值';
div.id = 'test';
div.className = 'navs';
// (2) element.setArribute('属性','值'); 主要针对自定义属性
div.setAttribute('index','2');
div.setAttribute('class','footer'); // class特殊,这里面写的就是class,不是className
2). 设置属性值
element.属性 = '值'; 设置内置属性值
element.setAttribute('属性','值');
区别:
element.属性 设置属性值
element.setAttribute('属性'); 主要设置自定义属性
3). 移除属性
// 3. 移除属性
// 移除属性 removeAttribute(属性);
div.removeAttribute('inex');
// 干点所有人,其余的li清除class这个类
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
// 留下我自己
this.className = 'current';
// 下面的显示内容模块
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';
4). H5自定义属性
// <div getTime="20" data-index="2" data-list-name="andy"></div>
var div = document.querySelector('div');
// console.log(ddiv.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']);
5. 节点操作
(1). 节点层级
1). 父级节点
node.parentNode
parentNode属性可返回某节点的父节点,注意是最近的一个父节点
如果指定的节点没有父节点则返回null
// 1. 父节点 parentNode
var bro = document.querySelector('.bro');
// var box = document.querySelector('.box');
console.log(bro.parentNode);
2). 子节点
1. parentNode.childNodes(标准)
parentNode.childNodes返回指定节点的字节点的集合,该集合为即时更新的集合。
注意:返回值包含了所有子节点,包括元素节点,文本节点等。
如果只想要获得里面的元素节点,则需要专门处理,所以我们一般不提倡使用childNodes
2. parentNode.children(非标准)
parentNode.children是一个只读属性,返回所有的子元素节点,其余节点不返回(重点)
虽然children是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用
var ul = document.querySelector('ul');
for (var i = 0; i < ul.childNodes.length; i++) {
if (ul.childNodes[i].nodeType == 1) {
// ul.childNode[i]是元素节点
console.log(ul.childNodes[i]);
}
}
3). DOM提供的方法(API)获取
// DOM提供的方法(API)获取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
// 1. 子节点childNodes所有字节点,包含:元素节点 文本节点等等
console.log(ul.childNodes);
console.log(ul.childNodes[0].nodeType);
console.log(ul.childNodes[1].nodeType);
// 2. children 获得所有的子元素节点,也是我们实际开发常用的
console.log(ul.children);
4). parentNode.firstElementChild
firstElementChild返回第一个子元素节点,找不到则返回null
5). parentNoe.lastElementChild
lastElementChild返回最后一个子元素节点,找不到返回null
注意:这两个方法有兼容性问题,IE9以上才支持。
var ol = document.querySelector('ol');
// 1. firstChild第一个子节点,不管是文本节点还是元素节点
console.log(ol.firstChild);
console.log(ol.lastChild);
// 2. firstElementChild返回第一个子元素节点
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
// 3. 实际开发的写法,既没有兼容性问题又返回第一个子元素
console.log(ol.children[0]);
console.log(ol.children[ol.children.length-1]);
实例:下拉菜单
// 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';
}
}
6). 兄弟节点
1. node.nextSibling
nextSibling返回当前元素的下一个兄弟节点,找不到则返回null,同样,也是包含所有节点
2. node.previousSibling
previousSibling返回当前元素上一个兄弟节点,找不到则返回null,同样,也是包含所有节点
3. node.nextElementSibling
nextElementSibling返回当前元素下一个兄弟元素节点,找不到返回null
node.previousElementSibling
previousElementSibling返回当前元素上一个兄弟元素节点,找不到返回null
注意: 这两个方法有兼容性问题,IE9以上才支持。
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);
// 兄弟节点解决兼容性问题(自己封装一个兼容性的函数)
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
(2). 创建节点
document.createElement('tagName')
document.createElement()方法创建由tagName指定的HTML元素。因为这些元素原先不存在,
是根据我们的需求动态生成的,所以我们也称为动态创建节点。
(3). 添加节点
1. node.appendChild(child)
node.appendChild()方法将一个节点添加到指定父节点列表末尾。类似于CSS里面的after伪元素
2. node.insertBefore(child, 指定元素)
node.insertBefore() 方法将一个节点添加到父节点的指定子节点前面。类似于CSS里面的before伪元素
// 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. 添加元素
留言框
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 注册事件
btn.onclick = function() {
if (text.value == '') {
alert('您没有输入内容');
return falsel;
}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]);
}
}
(4). 删除节点
node.removeChild(child)
node.removeChild() 方法从DOM中删除一个子节点,返回删除的节点
// 1. 获取元素
var ul = document.querySelector('ul');
var btn = document.querySelector('button');
// 2. 删除元素 node.removeChild(child)
// ul.removeChild(ul.children);
// 3. 点击按钮以此删除里面的孩子
btn.onclick = function() {
if (ul.children.length == 0) {
this.disabled = true;
}else {
ul.removeChild(ul.children[0]);
}
}
删除评论留言
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 注册事件
btn.onclick = function() {
if (text.value == '') {
alert('您没有输入内容');
return falsel;
}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);
}
}
}
}
(5). 复制节点(克隆节点)
node.cloneNode()
node.cloneNode() 方法返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点、
注意:
1. 如果括号参数为空或者false,则是浅拷贝,即只克隆复制节点本身,不克隆里面的字节点
2. 如果括号参数为true,则是深度拷贝,会复制节点本身以及里面所有的子节点
var ul = document.querySelector('ul');
// 1. node.cloneNode(); 括号为空或者里面是false,浅拷贝,只复制标签不复制里面的内容
// 2. node.cloneNode(true); 括号为true, 深拷贝,复制标签复制里面的内容
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
动态生成表格
// 1. 先去准备好数据
// var dates = [
// {
// name:'韩寒',
// subject:'javascript',
// score:98
// },{
// name:'猴子',
// subject:'javascript',
// score:99
// }
// ]
// 2. 往tbody里面创建行:有几个人(通过数组的长度)我们就创建几行
var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) { // 外面的for循环管行tr
// 创建tr行
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 行里面创建单元格td 单元格的数量取决于每个对象里面的属性个数,for循环遍历对象,datas[i]
for (var k in datas[i]) { // 里面的for循环管列 td
// 创建单元格
var td = document.createElement('id');
// 把对象里面的属性值datas[i][k] 给td
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)
}
}
(6). 三种动态创建元素的区别
(7). DOM重点
6. 事件高级
(1) 注册事件
1). 注册事件概述(绑定事件)
2). addEventListener事件监听方式
EventTarget.addEventListener(type,listener[, useCapture])
eventTarget.addEventListener() 方法将指定 监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:
type: 事件类型字符串,比如click, mouseover, 注意这里不要带on
listener: 事件处理函数,事件发生时,会调用该监听函数
useCapture: 可选参数,是一个布尔值,默认值是false。学完DOM事件流后,我们再进一步学习
var btns = document.querySelectorAll('button');
// 1. 传统方式注册事件
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('how are you!');
}
// 2. 事件监听注册事件,addEventListener
// (1) 里面的事件类型是字符串,必定加引号,而且不带on
// (2) 同一个元素,同一个事件可以添加多个监听器(事件处理程序)
btns[1].addEventListener('click', function() {
alert(33);
})
btns[1].addEventListener('click', function() {
alert(22);
})
// 3. attachEvent ie9以前的版本支持
btns[2].attachEvent('onclick', function() {
alert(1);
})
3). attachEvent 事件监听方式
eventTarget.attachEvent(eventNameWithOn, callback)
eventTarget.attachEvent() 方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,指定的回调函数就会被执行。
eventNameWithOn: 事件类型字符串,比如 onclick, onmouseover ,这里要带on
callback: 事件处理函数,当目标触发事件时回调函数被调用
注意:IE8及早期版本支持
4). 注册事件兼容性解决方案
function addEventListener(element, eventName,fn) {
// 判断当前浏览器是否支持 addEventListener 方法
if (element.addEventListener) {
element.addEventListener(eventName, fn); //第三个参数默认是false
}else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn);
}else {
// 相当于element.onclick = fn;
element['on' + eventName] = fn;
}
}
// 兼容性处理的原则:首先照顾大多数浏览器,再处理特殊浏览器
(2) 删除事件
1. 删除事件的方式
1). 传统注册方式
eventTarget.onclick = null;
2). 方法监听注册方式
(1) eventTarget.removeEventListener(type, listener[, useCapture]);
(2) eventTarget.detachEvent(eventNameWithOn, callback);
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
// 1. 传统方式删除事件
div[0].onclick = null;
}
// 2. removeEventListener 删除事件
divs[1].addEventListener('click', fn) // 里面的fn不需要调用加小括号
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
// 3.
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
2. 删除事件兼容性解决方案
function removeEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 removeEventListener 方法
if (element.removeEventListener) {
element.removeEventListener(eventName, fn); // 第三个参数,默认是false
} else if (elsment.detachEvent) {
element.detachEvent('on' + eventName, fn);
} else {
element['on' + eventName] = null;
}
}
(3) DOM事件流
<div>
<div class="son">son盒子</div>
</div>
// dom事件流三个阶段
// 1. Js代码中只能执行捕获或者冒泡其中的一个阶段
// 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
// 3. 捕获阶段,如果addEventListener 第三个参数是 true 那么则处于捕获阶段:document->html->body->father->son
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
}, true);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, true);
// 4. 冒泡阶段,如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段
// son->father->body->html->document
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
document.addEventListener('click', function() {
alert('document');
})
(4) 事件对象
1). 事件对象的兼容性方案
var div = document.querySelector('div');
div.onclick = function(e) {
// console.log(e);
// console.log(window.event);
e = e || window.event;
console.log(e);
}
// div.addEventListener('click', function(e) {
// console.log(e);
// })
// 1. event 就是一个事件对象,写到我们监听函数的小括号里面,当形参来看
// 2. 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
// 3. 事件对象是我们事件的一系列相关数据的集合,根事件相关的,比如鼠标点击里面就包含了鼠标的
// 相关信息:鼠标坐标啊,如果是键盘事件里面就包含了键盘事件的信息,比如:判断用户按下了那个键
// 4. 这个事件对象我们可以自己命名,比如event,evt,e
// 5. 事件对象也有兼容性问题 ie678 通过 window.event兼容性的写法 e = e || window.event;
2). 事件对象的常见属性和方法
// 常见事件对象的属性和方法
// 1. e.target 返回的是触发事件的对象(元素) this 返回的是绑定事件的对象(元素)
// 区别:e.target点击了那个元素,就返回那个元素 this 那个元素绑定了这个点击事件,那么就返回谁
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
console.log(e.target);
console.log(this);
})
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 我们给ul绑定了事件,那么this就指向ul
console.log(this);
console.log(e.currentTarget);
// e.target 指向我们点击的那个对象,谁触发了这个事件,我们点击的是li e.target 指向的就是li
console.log(e.target);
})
// 了解兼容性
div.onclick = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
console.log(target);
}
// 2. 了解跟this有个非常相似的属性 currentarget ie678不认识
// 事件对象阻止默认行为
// 1. 返回事件类型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
console.log(e.type);
}
// 2. 阻止默认行为(事件)让链接不跳转或者让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom标准写法
})
// 3. 传统注册方式
a.onclick = function(e) {
// 普通浏览器 e.preventDefault(); 方法
e.preventDefault();
// 低版本浏览器 ie678 returnValue 属性
e.returnValue;
// 我们可以利用return false 也能阻止默认行为,没有兼容性问题,特点:return 后面的代码不执行了,
// 而且只限于传统的注册方式
return false;
alert(11);
}
(5) 阻止事件冒泡
1). 阻止事件冒泡的两种方式
// 常见事件对象的属性和方法
// 阻止冒泡,dom推荐的标准 stopPropagation()
var son = document/querySelector('.son');
son.addEventListener('click', function() {
alert('son');
e.stopPropagation(); // stop停止Propagation传播
e.cancelBubble = true; // 非标准cancel取消bubble泡泡
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
document.addEventListener('click', function() {
alert('document');
})
2). 阻止事件冒泡的兼容性解决方案
if (e && e.stopPropagation) {
e.stopPropagation();
}else {
window.event.cancelBubble = true;
}
(6) 事件委托(代理,委派)
1. 事件委托
事件委托也称为事件代理,在JQuery里面称为事件委派。
2. 事件委托的原理
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后再利用冒泡原理影响设置每个子节点。
以下案例:给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,事件会冒泡到ul上,
ul有注册事件,就会触发事件监听器。
3. 事件委托的作用
我们只操作了一次DOM, 提高了程序的性能
事件委托的核心原理:给父节点添加监听器,利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function() {
alert('知否知否,点击出弹框');
// e.target 这个可以得到我们点击的对象
e.target.style.backgroundColor = 'blue';
})
(7) 常用的鼠标事件
1). 常用的鼠标事件
// 1. contextmenu我们可以禁用右键菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
// 2. 禁止选中文字 selectstart
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
2). 鼠标事件对象
event对象代表事件的状态,跟事件相关的一系列信息的集合。
现阶段我们主要是用鼠标事件对象:
MouseEvent 和键盘事件对象 KeyboardEvent。
// 鼠标事件对象 MouseEvent
document.addEventListener('click', function(e) {
// 1. client鼠标在可视区的x和Y坐标
console.log(e.clientX);
console.log(e.clientY);
console.log('-----------------------');
// 2. page 鼠标在页面文档的x和y坐标
console.log(e.pageX);
console.log(e.pageY);
console.log('-----------------------');
// 3. screen鼠标在电脑屏幕的x和y坐标
console.log(e.screen);
console.log(e.screenY);
})
小天使
<style>
img {
position: absolute;
top: 2px;
}
</style>
<img src="1.jpg" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove', function(e) {
// 1. mousemove只要我们鼠标移动1px,就会触发这个事件
// console.log(1);
// 2. 核心原理:鼠标每次移动,我们都会获得最新的鼠标坐标,把这个x和y坐标作为图片的top和left
// 就可以移动图片
var x = e.pageX;
var y = e,pageY;
console.log('x坐标是' + x, 'y坐标是' + y);
// 3. 不要忘记给left和top添加px单位
pic.style.left = x - 50 + 'px';
pic.style.top = y - 40 + 'px';
})
(8) 常用的键盘事件
1). 常用的键盘事件
// 1. keyup 按键弹起的时候触发
// document.onkeyup = function() {
// console.log('我弹起了');
// }
document.addEventListener('keyup', function(){
console.log('我弹起了');
})
// 2. keydown按键按下的时候触发,能识别功能键,比如ctr1 shift左右箭头等
document.addEventListener('keydown', function() {
console.log('我按下了down');
})
// 3. keypress按键按下的时候触发,不能识别功能键,比如ctrl shift 左右箭头等
document.addEventListener('keypress', function() {
console.log('我按下了press');
})
// 4. 三个事件的执行顺序 keydown -- keypress -- keyup
2). 键盘事件对象
键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
1. 我们的keyup和keydown事件不区分字母大小写 a 和 A 得到的都是65
2. 我们的keypress 事件区分字母大小写 a 97 和 A 得到的是65
// 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
// 1. 我们的keyup和keydown事件不区分字母大小写 a 和 A 得到的都是65
// 2. 我们的keypress 事件区分字母大小写 a 97 和 A 得到的是65
document.addEventListener('keyup', function(e) {
console.log(e);
console.log('up:' + e.keyCode);
// 我们可以利用keycode返回的ASCII码值来判断用户按下那个键
if (e.keyCode === 65) {
alert('您按下的a键');
} else {
alert('您没有按下a键')
}
})
document.addEventListener('keypress', function(e) {
console.log(e);
console.log('press:' + e.keyCode);
})
3). ASCII表
4). 模拟京东按键输入内容
// 模拟京东按键输入内容
// 核心思路:检测用户是否按下了s键,如果按下s键,就把光标定位到搜索框里面
// 使用键盘事件对象里面的keyCode判断用户按下的是否是s键
// 搜索框获得焦点:使用js里面的focus() 方法
var search = document.querySelector('input');
document.addEventListener('keyup', function(e) {
// console.log(e.keyCode);
if (e.keyCode === 83) {
search.focus();
}
})
5). 模拟京东快递单号查询案例
// 模拟京东快递单号查询案例
// 快递单号输入内容时,上面的大号字体盒子(con)显示(这里面的字号更大)
// 表单检测用户输入:给表单添加键盘事件
// 同时把快递单号里面的值(value)获取过来赋值给con盒子(innerText)作为内容
// 如果快递单号里面内容为空,则隐藏大号字体盒子(con)盒子
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
jd_input.addEventListener('keyup', function() {
console.log('输入内容啦');
if (this.value == '' ) {
con.style.display = 'none';
} else {
con.style.display = 'block';
con.innerText = this.value;
}
})
// 当我们失去焦点,就隐藏这个con盒子
jd_input.addEventListener('blur', function() {
con.style.display = 'nonde';
})
// 当我们获得焦点,就显示这个con盒子
jd_input.addEventListener('focus', function() {
if (this.value !== '') {
con.style.display = 'block';
}
})