【前端】前端三要素之DOM

写在前面:本文仅包含DOM内容,JavaScript传送门在这里,BOM传送门在这里。

本文内容是假期中刷的黑马Pink老师视频(十分感谢Pink老师),原文保存在个人的GitLab中,如果需要写的网页内容信息等可以评论联系我,若是编辑博文中出现了忘记上传的图片或者错位的图片欢迎评论区指正。写作不易,欢迎点赞、收藏+关注。

文章目录

  • DOM
    • DOM 专有名词
        • DOM树
    • DOM 获取元素
  • DOM | 事件
    • 点击按钮事件示例
    • 执行事件过程
    • 鼠标到Div上跳出弹框示例
  • 操作元素
    • 修改元素内容
    • 示例 | 鼠标移动进去显示中文,离开显示英文
    • 区别 | innerText 与 innerHTML 的区别
    • 通过innetText 和 innerHTML 获取文字内容
        • innerText
        • innerHTML
    • 修改元素属性
    • 表单属性操作
        • 修改表单文字
        • 示例 | 输入密码
    • 表单样式修改
        • 示例 | 修改背景颜色
        • 示例 | 淘宝精灵图
        • 示例 | 得到焦点与失去焦点
    • 使用`className`修改样式
    • 自定义属性值
  • 节点操作
    • node.parentNode | 获取父节点
    • node.childNodes | 获取子节点
    • 获取特定子节点
    • 获取兄弟节点
        • 获取下一个兄弟节点
        • 获取上一个兄弟节点
    • 创建节点
    • 删除节点
    • 拷贝节点
    • `document.write()` | 不推荐
  • 监听事件
    • 方式比较:
        • 传统方式
        • 监听事件
    • 添加监听事件
    • 解绑事件
  • 事件流
    • 事件执行流程
        • 捕获阶段
        • 目标节点
        • 冒泡阶段
    • 验证
  • 事件对象
    • 获取事件对象
        • 传统方式获取事件对象
        • 监听方式获取事件对象
        • 在ie678中使用监听对象
    • 事件对象的常见属性和方法
    • 阻止默认行为
  • 阻止冒泡事件
  • 事件委托
        • 示例
  • 禁用鼠标右键
  • 禁用文字选择
  • 获取鼠标坐标信息
  • 常用键盘事件
        • `keydown` | 键盘被按下
        • `keyup` | 键盘弹起事件
        • `keypress` | 键盘按下事件
    • 按下s键输入框获取焦点案例

DOM

DOM 专有名词

DOM树
  1. 文档:一个页面就是一个文档,DOM中使用Document表示
  2. 元素:页面中所有的标签都是元素,DOM中使用element表示
  3. 节点:网页中所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示

在这里插入图片描述

DOM 把以上内容都看做事对象。

DOM 获取元素

  1. 通过ID获取 | getElementById()
  2. 通过标签名获取
  3. 通过HTML5新增方法获取
  4. 特殊元素获取
  1. 通过ID获取 | getElementById()

返回的是一个

<body><div id="time">2019-9-9</div><script>var time = document.getElementById('time');console.log(time);console.log(typeof time); // 返回的是一个元素对象console.log(time.id);console.dir(time); // div#time</script>
</body>
  1. 根据标签名获取 | getElementsByTagName() | 返回的是对象集合
<body><ul><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li></ul><script>var eles = document.getElementsByTagName('li');console.log(eles); // HTMLCollections(5) [li,li,li,li,li]// 逐个输出一下for( var i = 0; i < eles.length ; i ++) {console.log(eles[i]);}</script>
</body>

得到元素对象是动态的,如果元素的内容发生了变化,JS获取到的内容跟着一起变化

注意事项

  1. 如果页面中只有一个元素,返回的也是一个伪数组
  2. 如果页面中没有元素,返回的是一个空的伪数组

通过父元素获取其全部子元素

<body><ul><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li><li>知否知否,应是绿肥红瘦。</li></ul><ol><li>哈哈哈</li><li>哈哈哈</li><li>哈哈哈</li><li>哈哈哈</li></ol><script>var ol = document.getElementsByTagName('ol');var lis = ol[0].getElementsByTagName('li');console.log(lis);</script>
</body>
  1. HTML5新增的方法 | 通过类名获取 | getElementsByClassName()
<body><div class="box">123</div><div class="box">123</div><div class="box">123</div><script>var lis = document.getElementsByClassName('box'); // 长度为3的伪数组</script>
</body>
  1. querySelectir()
  1. querySelector():获取指定选择器的第一个元素
  2. querySelectorAll():获取页面上所有元素
<body><div class="box">hahaha</div><div class="box">hahaha</div><div class="box">hahaha</div><script>var firstBox1 = document.querySelector('.box'); // 通过.告诉选择器这是一个class | <div class="box">hahaha</div>var firstBox2 = document.querySelector('#box'); // 通过#告诉选择器这是一个id | nullconsole.log(firstBox1);console.log(firstBox2);</script>
</body>
  1. querySelectirAll() | 获取所有元素
<body><div class="box">hahaha</div><div class="box">hahaha</div><div class="box">hahaha</div><script>var firstBox1 = document.querySelectorAll('.box'); // 通过.告诉选择器这是一个class | <div class="box">hahaha</div>var firstBox2 = document.querySelectorAll('#box'); // 通过#告诉选择器这是一个id | nullconsole.log(firstBox1); // 长度为3的伪数组console.log(firstBox2); // 空的伪数组</script>
</body>
  1. 获取特殊标签 | body、htlm

一般来说只有一个body标签或者一个htlm标签

  1. 获取 BODY
<body><script>var bodyEle = document.body;console.log(bodyEle); // 输出Body对象</script>
</body>
  1. 获取 HTML
<body><script>var htmlEle = document.documentElement;console.log(htmlEle); // HTML 对象</script>
</body>

DOM | 事件

JavaScript 使我们有能力创建动态页面,而时间是可以被JavaScript侦测到的行为

简单理解:出发—响应机制

网页中的每个元素都可以产生某些可以出发JavaScript的事件,例如,我们可以在用户点击某个按钮的时候产生一个事件,然后去执行某些操作。

事件是由三部分组成:事件源、事件类型、事件处理程序(一般称为事件三要素)

  1. 事件源:时间的触发的对象,是由谁来触发,比如按钮
  2. 事件类型:如何出发,比如鼠标点击出发、鼠标经过出发、键盘按下触发
  3. 事件处理程序:通过一个函数赋值的方式完成

点击按钮事件示例

<body><button id="btn">点击一下</button><script>var btn = document.getElementById('btn');btn.onclick = function () {alert('点击了一下~');}</script>
</body>

执行事件过程

  1. 获取事件源
  2. 注册时间(绑定事件)
  3. 添加事件处理程序(采用函数赋值形式)

鼠标到Div上跳出弹框示例

<body><div style="background: antiquewhite;text-align: center;width: 200px;border-radius: 5px;box-shadow: 0 0 3px gray">123</div><script>var div = document.querySelector('div');div.onmouseover = function (){alert('Hello World~');}</script>
</body>
鼠标事件描述
onclick鼠标点击左键触发
onmouseover鼠标经过触发
onmouseenter鼠标进入触发
onmouseout鼠标离开触发
onfocus获取鼠标焦点触发
onblur失去鼠标焦点触发
onmousemove鼠标移动触发
onmousedown鼠标按下触发
onmouseup鼠标弹起触发
contextmenu右键的时候触发
selectstart选择文字的时候触发

注意:mouseover存在冒泡事件,经过自身盒子会触发事件,子盒子也会触发。mouseenter不存在冒泡事件,只有经过自身时才会触发。

操作元素

修改元素内容

  1. element.innerText | 起始位置稻种植未知的内容,但它去除Html标签,同时空格和空行也会去掉
  2. element.innerHTML | 起始位置到终止位置的全部内容,包括html,同时保留空格和换行

示例 | 鼠标移动进去显示中文,离开显示英文

<body><button>显示中文</button><div style="background: antiquewhite;border: .1px solid gray">Hello World</div><script>//1. 获取元素var btn = document.querySelector('button');var div = document.querySelector('div');btn.onmouseover = function () {div.innerText = '你好,世界!'}btn.onmouseleave = function () {div.innerText = 'Hello World'}</script>
</body>

鼠标移动上去显示中文,鼠标移出之后显示英文。

在这里插入图片描述

区别 | innerText 与 innerHTML 的区别

innetText:它会原封不动的将我们给它的字符串显示到页面上(无法识别HTML标签)

innerHTML:如果发现是html标签,它会解析html标签并显示

尽量使用innerHTML,这是W3C发布的标准

<body><button>点击加粗名字</button><div>我是Jim.kk</div><script>var btn = document.querySelector('button');var div = document.querySelector('div');btn.onclick = function () {div.innerHTML = '<b>我是Jim.kk</b>';}</script>
</body>

在这里插入图片描述

如果是使用innerText的方式的话,则会原封不动的显示双引号的内容,下面看示例:

<body>
<button>点击加粗名字</button>
<div>我是Jim.kk</div>
<script>var btn = document.querySelector('button');var div = document.querySelector('div');btn.onclick = function () {div.innerText = '<b>我是Jim.kk</b>';}
</script>
</body>

在这里插入图片描述

通过innetText 和 innerHTML 获取文字内容

两者的区别在于:innerText只会获取文字

innerText
<body><p>一段文字:<span>我是Jim.kk</span></p><script>var p = document.querySelector('p');console.log(p.innerText); // 一段文字: 我是Jim.kk</script>
</body>

在这里插入图片描述

innerHTML
<body><p>一段文字:<span>我是Jim.kk</span></p><script>var p = document.querySelector('p');console.log(p.innerHTML); // 一段文字:(换行)<span>我是Jim.kk</span></script>
</body>

在这里插入图片描述

修改元素属性

  1. src、href
  2. id、alt、title
<body><button id="btn1">图片1</button><button id="btn2">图片2</button><div style="margin-top: 20px"><img src="img/img1.png" alt="" style="width: 500px" title="IMG1"></div><script>// 修改图片属性var btn1 = document.getElementById('btn1');var btn2 = document.getElementById('btn2');var img  = document.querySelector('img');btn1.onclick = function () {img.src = 'img/img1.png';img.title = 'IMG1';}btn2.onclick = function () {img.src = 'img/img2.png';img.title = 'IMG2';}</script>
</body>

以上代码点击按钮2显示一张图片,点击按钮1又会变回来

表单属性操作

修改表单文字

type、value、checked、selected、disabled

<body><input type="text" value="请输入内容"><button id="btn1">按钮</button><button id="btn2">禁用</button><script>// 1. 获取元素var btn1 = document.getElementById('btn1');var btn2 = document.getElementById('btn2');var input = document.querySelector('input');btn1.onclick = function () {input.value = '123';}btn2.onclick = function () {input.disabled = true;this.disabled = true;  // this指向的是btn,谁调用函数就指向谁,这里是btn2}</script>
</body>

在这里插入图片描述

示例 | 输入密码

点击小眼睛显示密码,同时小眼睛睁开
再次点击隐藏密码,同时小眼睛关闭

<body><div class="box"><label for=""><img src="img/icons/close.png" alt="" id="eye"></label><input type="password" name="" id="pwd"></div><script>var btn = document.getElementById('eye');var pwd = document.getElementById('pwd');var flag = 0;btn.onclick = function () {if(flag === 0) {this.src = 'img/icons/open.png'pwd.type='text';flag = 1;} else {this.src = 'img/icons/close.png'pwd.type='password';flag = 0;}}</script>
</body>

表单样式修改

可以用以下两种方式修改:

  1. element.style='background: red';
  2. element.style.background='red';

区别在于,第一种方式可以在引号内写入很多样式,第二种需要一个样式定义一行

示例 | 修改背景颜色

设置一个DIV,鼠标移入之后改变背景颜色,示例如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>样式操作1</title><style>div {width: 200px;height: 200px;background: antiquewhite;}</style>
</head>
<body>
<div></div>
<script>var div = document.querySelector('div');div.onmouseover = function () {div.style = 'background: red';}div.onmouseleave = function () {div.style = 'background: antiquewhite';}
</script>
</body>
</html>

或者像下面这么写:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>样式操作2</title><style>div {width: 200px;height: 200px;background: antiquewhite;}</style>
</head>
<body><div></div><script>var div = document.querySelector('div');div.onmouseover = function () {div.style.background = 'red';}div.onmouseleave = function () {div.style.background = 'antiquewhite';}</script>
</body>
</html>
示例 | 淘宝精灵图
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><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: pink;margin: 15px;background: url(img/icons/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. 获取所有livar lis = document.querySelectorAll('li');for (var i = 0; i < lis.length ; i++){// 让索引号*44获取每个li的背景y坐标var index = i * 44;lis[i].style.backgroundPosition = '0 -' + index + 'px'}</script>
</body>
</html> 
示例 | 得到焦点与失去焦点

以下示例有一个磨人的输入框,若是输入框的默认值是’手机’,则在得到焦点的时候清空输入框,若是失去焦点的时候输入框内容是空的,则显示手机。

<body><input type="text" value="手机"></input><script>var input = document.querySelector('input');input.onfocus = function () {// console.log('得到焦点');if ( input.value === '手机' ) {this.value = '';}}input.onblur = function () {if ( input.value === '' ) {input.value = '手机';}}</script>
</body>

使用className修改样式

上述方法是一条一条的style属性,除了以上方法外,我们还可以同时定义多个div,然后通过element.className='divName'的方式修改它的样式

如果想要即保留原来的类名,有来个新的类名,只需要element.className='oldDivName newDivName'

下面源码是个很好的示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>className</title><style>.div1{height: 50px;background: antiquewhite;box-shadow: 0 0 5px gray;border: 3px solid gray;border-radius: 5px;}.div2{height: 100px;background: red;box-shadow: 0 0 20px gray inset;border: .1px solid gray;border-radius: 50px;}</style>
</head>
<body><div class="div1"></div><script>var div = document.querySelector('div');div.onmouseenter = function () {div.className = 'div2';}div.onmouseleave = function () {div.className = 'div1';}</script>
</body>
</html>

自定义属性值

  1. 通过element.getAttribute('')可以获取属性
  2. 这种方式可以获取自定义属性
  3. 通过element.setAttribute('属性名','属性值'')可以为元素自定义属性
  1. 通过getAttribute获取自定义属性值

div中本来是不存在index这个内置属性的,但是我们设置之后可以通过getAttribute来获取:

<body><div index="1" id="div1"></div><script>var div = document.querySelector('div');console.log(div.getAttribute('id')); // div1console.log(div.getAttribute('index')); // 1</script>
</body>
  1. 通过setAttribute设置自定义属性

除了直接将自定义属性写在标签里面以外,还可以通过setAttribute的方式设置自定义属性

<body><div id="div1"></div><script>var div = document.querySelector('div');div.setAttribute('xx','123');console.log(div.getAttribute('xx')); // 123// 修改内置属性值div.setAttribute('id','divx');console.log(div.getAttribute('id')); // divx</script>
</body>
  1. H5 新标准

H5新标准中,规定所有的自定义属性都得以data-开头,所以又新增了dataset方法让我们获取自定义属性

这种方法只能获取data-开头的自定义属性

<div data-index="1" data-list-name="Jim.kk"></div>
<script>var div = document.querySelector('div');console.log(div.dataset.index); // 1console.log(div.dataset['index']) // 1console.log(div.dataset.listName); // Jim.kkconsole.log(div.dataset['listName']) // Jim.kk
</script>

节点操作

什么是节点?网页中所有的内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node来表示。

HTML DOM树种的所有节点均可通过JavaScript进行访问,所有的HTML元素(节点)均可被修改,也可以被创建或者删除。

节点一般由:nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。

在这里插入图片描述

以上截图对应以下代码(注意,由于没有规定编码,在浏览器中打开可能存在乱码):

<html lang="en"><head><title>节点操作</title></head><body><a href="www.baidu.com">我的链接</a><h1>我的标题</h1></body>
</html>

利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。

node.parentNode | 获取父节点

<body><div><span>新年快乐!龙年行大运!!!</span></div><script>var span = document.querySelector('span');var div = span.parentNode;console.log(div);</script>
</body>

node.childNodes | 获取子节点

childNode默认会获得所有的子节点,包括文字和标签,所以以下代码输出的node长度为9(有五个换行)

如果不想要换行(毕竟也没什么用),可以使用children来代替childNode

children并不是官方的,但是获得了各浏览器的支持,所以放心使用。

<body><ul><li>新年快乐!龙年行大运!!!</li><li>新年快乐!龙年行大运!!!</li><li>新年快乐!龙年行大运!!!</li><li>新年快乐!龙年行大运!!!</li></ul><ul><li>我是Jim.kk!!!</li><li>我是Jim.kk!!!</li><li>我是Jim.kk!!!</li><li>我是Jim.kk!!!</li></ul><script>var ul = document.querySelector('ul');console.log(ul.childNodes); // NodeList(9) [text, li, text, li, text, li, text, li, text]console.log(ul.children); // HTMLCollection(4)</script>
</body>

获取特定子节点

可以使用firstChild来获取第一个节点,但是这种获取方式仍然会获取换行等文本节点

方法说明备注
element.firstChild获取第一个元素,但是会包含文本信息,也就是会获取你的换行等信息
element.lastChild获取最后一个元素,但是会包含文本信息,也就是会获取你的换行等信息
element.firstElementChild获取第一个元素,不包含文本信息,也就是只获取标签元素IE9以上才支持
element.lastElementChild获取最后一个元素,不包含文本信息,也就是只获取标签元素IE9以上才支持
element.children[0]用下标的方式获取某个指定的元素实际开发中的用法

获取兄弟节点

获取下一个兄弟节点
方法说明备注注意
nextSibling获取下一个兄弟节点也会获取text节点
nextElementSibling获取下一个兄弟节点只会获取标签节点IE9以上才支持
<body><div>新年快乐!龙年行大运</div><span>我是Jim.kk</span><script>// 下一个兄弟节点存在var div = document.querySelector('div');console.log(div.nextSibling) // #textconsole.log(div.nextElementSibling) // span// 下一个兄弟节点是Scriptvar span = document.querySelector('span');console.log(span.nextSibling) // #textconsole.log(span.nextElementSibling) // <script>// 下一个兄弟节点不存在var script = document.querySelector('script');console.log(script.nextSibling) // <link type="text/css" rel="stylesheet" id="dark-mode-custom-link">console.log(script.nextElementSibling) // <link type="text/css" rel="stylesheet" id="dark-mode-custom-link"></script>
</body>
获取上一个兄弟节点
方法说明备注注意
previousSibling获取上一个兄弟节点也会获取text节点
previousElementSibling获取上一个兄弟节点只会获取标签节点,如果不存在则会返回nullIE9以上才支持
<body><div>新年快乐!龙年行大运</div><span>我是Jim.kk</span><script>var span = document.querySelector('span');console.log(span.previousSibling); // #textconsole.log(span.previousElementSibling); // <div>新年快乐!龙年行大运</div>// 当前节点是第一个节点,会获取一个空var div = document.querySelector('div');console.log(div.previousSibling) // #textconsole.log(div.previousElementSibling) // null</script>
</body>

创建节点

  1. 创建一个节点 | document.createElement();
  2. 添加到某个地方去
    2.1 fatherElement.appendChild(childElement); | 在父节点内部追加节点
    2.2 fatherElement.insertBefore(childElement,fatherElement.children[0]); | 在父节点内部的某个子节点前面插入这个元素
<body><ul></ul><script>var li1 = document.createElement('li');var ul = document.querySelector('ul');ul.appendChild(li1); // 在ul的子节点中追加这个元素var li2 = document.createElement('li');ul.insertBefore(li2,ul.children[0]); // 在ul的0号元素前面插入一个li2</script>
</body>

删除节点

  1. node.removeChild() | 删除父亲中的某个孩子
<body><ul><li>兔年</li> <!-- 打错了,删除掉 --><li>龙年</li><li>行大运</li></ul><script>// 1. 获取元素var ul = document.querySelector('ul');// 2. 删除元素ul.removeChild(ul.children[0]);</script>
</body>

拷贝节点

我们可以使用node.cloneNode()来拷贝节点,但是如果括号中为空或者是false,则只会克隆节点本身,而不会克隆里面的子节点,如果想要克隆里面的子节点,我们在括号内写入true即可。

<body><ul><li>1</li><li>2</li><li>3</li></ul><script>var ul = document.querySelector('ul');// 1. node.cloneNode();var li1 = ul.children[0].cloneNode();ul.appendChild(li1); // 节点为空 | 因为上面的括号参数为空或者false,是浅拷贝,则只克隆节点本身,不克隆里面的子节点var li2 = ul.children[0].cloneNode(true);ul.appendChild(li2); // 节点为空 | 因为上面的括号参数为空或者false,是浅拷贝,则只克隆节点本身,不克隆里面的子节点</script>
</body>

document.write() | 不推荐

document.write是直接将内容写入页面的内容流,但是文档流执行完毕,会导致页面全部重绘。

简单解释下:若是我们在页面加载的时候就直接在script中写入document.write,那么里面的元素会追加在页面的最下面,但是若是通过页面中一个按钮点击后再加载的话,那么整个页面会只剩下这一个元素。

示例如下:

  1. 直接加载元素
<body><p>abc</p><script>var btn = document.querySelector('button');document.write('<div>我是Jim.kk</div>');</script>
</body>

在这里插入图片描述

可以看到,由于页面加载的时候就已经执行了这个方法,所以该方法中的内容是被追加到页面最下面的。

<body><button>点击</button><p>abc</p><script>var btn = document.querySelector('button');btn.onclick = function () {document.write('<div>我是Jim.kk</div>')}</script>
</body>

在这里插入图片描述

由于页面已经渲染完毕,这时候我们点击按钮写入这个元素,页面中的内容直接被覆盖了,只留下了我们写入的元素(建议自己试验一下试试效果)。

监听事件

给元素添加事件,称为注册事件或者绑定事件

注册事件有两种方式:传统方式方法监听注册方式

方式比较:

传统方式
  1. 传统方式利用on开头的事件,比如onclickonmouseenter
  2. 特点:注册事件的唯一性
  3. 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数会覆盖前面注册的处理函数。

下面代码中,由于我们给btn先后注册了两个点击事件,所以后面的点击事件会覆盖掉前面的点击事件,点击之后会跳出弹框’Hello~’

<body><button>点击</button><script>var btn = document.querySelector('button');btn.onclick = function () {alert('Hi~')}btn.onclick = function () {alert('Hello~')}</script>
</body>

在这里插入图片描述

监听事件
  1. W3C 标准 推荐方式
  2. addEventListener() 是一个方法
  3. IE9之前的IE浏览器不支持此方法,可以使用attachEvent()代替
  4. 同一个元素,同一个事件可以添加多个

添加监听事件

书写方式: eventTarget.addEventListener(type,listener[,useCapture])
eventTarget.addEventListener() 方法将制定的监听器注册到eventTarget上(目标对象),当该对象出发指定的事件时,就会执行事件处理函数。

  1. type:事件类型字符串,比如clickmouseover,注意这里不带on
  2. listener:事件处理函数,事件发生时,会调用该监听函数
  3. useCapture:可选参数,是一个布尔值,默认是false。

添加监听事件的两个方法:

方法说明备注
addEventListenerIE9以后才支持推荐
attachEventIE9以前才支持
<body><button>监听事件</button><script>// 2. 监听事件var btn = document.querySelector('button');btn.addEventListener('click',function () {alert('Hello World');})btn.addEventListener('click',function () {alert('我是Jim.kk');})</script>
</body>

以上代码点击按钮之后,会连续跳出两次弹框,第一个弹框显示Hello World,当你关闭该弹框之后,会再次跳出一个弹框,显示我是Jim.kk

解绑事件

  1. 传统方式中,我们可以使用element.onclick = null的方式解绑事件
  2. 监听事件中,我们要移除事件,就不能再用匿名函数了,而是要给函数一个名字,然后removeEventListener这个事件
<body><!-- 传统方式 --><button id="btn1">传统事件</button><script>var btn = document.querySelector('#btn1');btn.onclick = function () {alert('我是Jim.kk');btn.onclick = null; // 解绑事件,再次点击就没用了}</script><!-- 监听方式 --><button id="btn2">监听方式</button><script>var btn = document.querySelector('#btn2');function fun() {alert('Jim.kk祝大家新年快乐!!');btn.removeEventListener('click',fun)}btn.addEventListener('click',fun);</script>
</body>

在IE9之前的浏览器中,我们只能使用attachEvent添加监听函数,在这种情况下我们要使用detachEvent的方式来移除事件,用法与removeEventListener无异,这里不做演示。

事件流

事件执行流程

事件流描述的是从页面中接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
比如我们给DIV注册了点击事件
DOM事件流分为三个阶段:

  1. 补货阶段
  2. 当前目标节点
  3. 冒泡阶段

在这里插入图片描述

捕获阶段
  1. 虽然我是给Div添加的点击事件,但是点击事件的接收者是Document
  2. Document并没有绑定这个点击事件,接下来向下找,找到html
  3. html也没有绑定,继续向下找找到body
  4. body也没有绑定,接下来找到div,这时候发现div绑定了这个事件
目标节点
  1. 找到div之后,进入到当前目标阶段,开始执行事件
冒泡阶段
  1. div执行事件结束,将事件向上传播,依次给body-html-Document,这里就是冒泡阶段

事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后主机箱上传播到DOM最顶层节点的过程

事件捕获:网景公司最早提出,有DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收过程

验证

如果addEventListener第三个参数是true,那么则处于捕获阶段,执行顺序是由外向内,也就是document-html-body-target
如果addEventListener第三个参数是false或者空,那么则处于冒泡阶段,执行顺序是由内到外,也就是target-body-html-document

以下代码点击之后先弹出father框,关闭后再弹出son

<head><meta charset="UTF-8"><title>事件流</title><style>.father {width: 400px;height: 400px;margin: 200px auto;padding: 50px;background: antiquewhite;}.son {background: gray;width: 100%;height: 100%;}</style>
</head>
<body><div class="father"><div class="son">son盒子</div></div><script>// dom 事件流三阶段:// 1. JS 代码中只能执行捕获或者冒泡其中一个阶段// 2. onclick 和 attachEvent(ie)只能得到冒泡阶段// 3. 捕获阶段,如果addEventListener第三个参数是true,那么则处于捕获阶段 document-html-body-father-sonvar son = document.querySelector('.son');son.addEventListener('click',function () {alert('son');}, true);var father = document.querySelector('.father');father.addEventListener('click',function () {alert('father');}, true)</script>
</body>

以下代码点击后先弹出son框,再弹出father框,最后弹出document框。

<head><meta charset="UTF-8"><title>事件流</title><style>.father {width: 400px;height: 400px;margin: 200px auto;padding: 50px;background: antiquewhite;}.son {background: gray;width: 100%;height: 100%;}</style>
</head>
<body><div class="father"><div class="son">son盒子</div></div><script>// 4. 冒泡阶段:如果addEventListener第三个参数是false,或者省略,那么就是冒泡阶段,执行顺序 son-father-body-html-documentvar son = document.querySelector('.son');son.addEventListener('click',function () {alert('son');});var father = document.querySelector('.father');father.addEventListener('click',function () {alert('father');});document.addEventListener('click',function () {alert('document');})</script>
</body>

事件对象

  1. event 就是一个事件对象,写到侦听函数的小括号中
  2. 事件对象只有有了事件才会存在,它是系统自动创建的,无需传递参数
  3. 事件对象是事件相关的一系列相关数据的集合,跟事件相关,比如鼠标点击里面就包含了鼠标的相关信息,如果是键盘事件里面就包含了键盘的信息,比如:判断用户按下了哪个键
  4. 事件对象不一定非要写成event,名字可以随便写
  5. 事件对象也有兼容性问题,ie678通过window.event获取事件对象。

获取事件对象

传统方式获取事件对象
<body><div>一个盒子</div><script>var div = document.querySelector('div');div.onclick = function (event) {// 1. event 就是一个事件对象,写到侦听函数的小括号中// 2. 事件对象只有有了事件才会存在,它是系统自动创建的,无需传递参数// 3. 事件对象是事件相关的一系列相关数据的集合,跟时间相关,比如鼠标点击里面就包含了鼠标的相关信息,如果是键盘事件里面就包含了键盘的信息,比如:判断用户按下了哪个键console.log(event);}</script>
</body>

以上代码点击之后会在控制台输出鼠标的相关信息,如截图中所示:

在这里插入图片描述

监听方式获取事件对象

以下代码的执行顺序与上面代码无异,不做演示

<body><div>一个盒子</div><script>var div = document.querySelector('div');div.addEventListener('click',function (event) {console.log(event);})</script>
</body>
在ie678中使用监听对象
<body><div>一个盒子</div><script>var div = document.querySelector('div');div.addEventListener('click',function (event) {console.log(event); // undefinedconsole.log(window.event); // 事件对象})</script>
</body>

事件对象的常见属性和方法

事件对象属性方法说明备注
e.target返回触发事件的对象标准
e.srcElement返回触发事件的对象非标准 ie678使用
e.type返回时间的类型,比如’click’、‘mouseover’不带on
e.cancelbubble该属性组织冒泡非标准 ie678使用
e.returnValue该属性组织默认时间(默认行为)非标准 ie678使用,比如不让连接跳转
e.preventDefault()该方法阻止默认事件(默认行为)标准,比如不让链接跳转
e.stopPropagation()阻止冒泡标准
  1. this:我们给谁绑定了事件,那么this就指向谁
  2. event.target:指向我们点击的那个对象
  3. event.currentEvent类似于this,但是ie678不支持

阻止默认行为

什么是默认行为?比如a标签是跳转。

<body><a href="https://baidu.com">百度</a><script>var a = document.querySelector('a');// 1. 监听方式a.addEventListener('click',function (e) {e.preventDefault(); // DOM 标准写法})// 2. 传统方式a.onclick = function (e) {// 普通浏览器 e.preventDefault(); 方法e.preventDefault();// 低版本浏览器 ie678 returnValue 属性e.returnValue;// 也可以使用return false 阻止默认方法,没有兼容问题return false;}</script>
</body>

其中监听浏览器只能使用e.preventDefault()的写法

传统方式可以采用三种方式

  1. e.preventDefault();
  2. e.returnValue; // 仅支持 ie678
  3. return false; 最推荐的写法,没有兼容问题

阻止冒泡事件

冒泡事件:开始时由最具体的元素接收,然后主机箱上传播到DOM最顶层节点。

事件冒泡本身的特定会带来一定的好处,也会带来一定的坏处,需要我们灵活掌握。

阻止冒泡排序

  1. stopPropagation()方法

在事件方法中对事件对象使用stopPropagation()即可

在ie678中使用window.event.cancelBubble = true;的写法

事件委托

事件委托也称为事件代理,在jQuery里面成为事件委派。

不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。

示例

ul注册点击事件,然后利用时间对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器。

一起看一下以下代码:

  1. 我们给父元素ul添加点击事件,这样当我们点击子元素li之后,就会通过冒泡的方式传递到ul
  2. 我们在点击事件中通过target获取我们点击的元素,然后给它一个背景颜色
  3. 完美
<body><ul><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li><li>弹框咯</li></ul><script>var ul = document.querySelector('ul');ul.addEventListener('click',function (e) {e.target.style.backgroundColor = 'pink';})</script>
</body>

禁用鼠标右键

<script>document.addEventListener('contextmenu',function (e) {e.preventDefault();})
</script>

注意:由于是监听事件,不支持return false;的写法,必须要用e.preventDefault();

禁用文字选择

<body><span>我是Jim.kk</span><script>document.addEventListener('selectstart',function (e) {e.preventDefault();})</script>
</body>

获取鼠标坐标信息

鼠标事件对象说明备注
e.clientX返回鼠标相对于浏览器窗口可视区的X坐标
e.clientY返回鼠标相对于浏览器窗口可视区的Y坐标
e.pageX返回鼠标相对于文档页面的X坐标IE9+ 支持
e.pageY返回鼠标相对于文档页面的Y坐标IE9+ 支持
e.screenX返回鼠标相对于电脑屏幕的X坐标
e.screenY返回鼠标相对于电脑屏幕的Y坐标
<head><meta charset="UTF-8"><title>获取鼠标坐标 </title><style>body {height: 3000px;}</style>
</head>
<body>
<script>document.addEventListener('click',function (e) {console.log(e.clientX); // 可视窗口的X坐标(纯网页部分)console.log(e.clientY); // 可视窗口的Y坐标(纯网页部分)console.log(e.pageX);   // 页面上的X坐标(若是页面发生了滚动,则该值也会增大缩小,clientX/Y不会)console.log(e.pageY);   // 页面上的X坐标(若是页面发生了滚动,则该值也会增大缩小,clientX/Y不会)console.log(e.screenX); // 当前屏幕的坐标,包含浏览器上册的操作栏部分console.log(e.screenY); // 当前屏幕的坐标,包含浏览器上册的操作栏部分})
</script>
</body>

以上代码点击后输出内容如下所示(页面已经滚动):

在这里插入图片描述

常用键盘事件

键盘事件触发条件备注
onkeyup某个按键松开时触发
onkeydown某个按键按下时触发
onkeypress某个按键按下时被触发可以区分字母大小写,但是不能识别功能键,比如:ctrl、shift、箭头等
keydown | 键盘被按下
<body>
<script>document.addEventListener('keydown',function (e) {console.log(e.key+"被按下了");})
</script>
</body>

以上代码,当我在页面上按住"s"键不放,效果如下:

在这里插入图片描述

keyup | 键盘弹起事件

与键盘按下不太一样,当键盘持续被按着时,键盘按下事件会一直被触发,但是键盘弹起事件只有在弹起的时候会被触发一次,见以下代码。

<body><script>document.addEventListener('keyup',function (e) {console.log(e.key+"弹起了");})</script>
</body>

以上代码在我点击键盘后(长按弹起后才会生效),控制台输出如下:

在这里插入图片描述

keypress | 键盘按下事件

与上面两个方法不同的是,keypress按钮对功能键不生效。

<body><script>document.addEventListener('keypress',function (e) {console.log(e.key+"被按下了");})</script>
</body>

以上代码当我在键盘上分别点击asdfctrl键后,控制台输出如下:

在这里插入图片描述

可以看到,ctrl键并没有生效。

我们可以通过event.key来获取键盘的值,或者event.keyCode来获取ASCII码值。

按下s键输入框获取焦点案例

<body><input type="text"><script>var search = document.querySelector('input');document.addEventListener('keyup',function (e) {if ( e.key === 's') {search.focus();}})</script>
</body>

以上代码用户在页面中点击s键,输入框就会获取焦点,用户就可以在输入框中输入内容了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/694402.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3 + ts + echart 实现柱形图表

首先封装Echart一个文件 代码如下 <script setup lang"ts"> import { ECharts, EChartsOption, init } from echarts; import { ref, watch, onMounted, onBeforeUnmount } from vue;// 定义props interface Props {width?: string;height?: string;optio…

pclpy 窗口可视化多个点云

pclpy 窗口可视化多个点云 一、算法原理二、代码三、结果1.可视化结果 四、相关数据五、问题与解决方案1.问题2.解决 一、算法原理 原理看一下代码写的很仔细的。。目前在同一个窗口最多可视化两个点云。。 二、代码 from pclpy import pcldef CloudShow(cloud1, cloud2):&q…

04 动力云客之登录后获取用户信息+JWT存进Redis+Filter验证Token + token续期

1. 登录后获取用户信息 非常好实现. 只要新建一个controller, 并调用SS提供的Authentication对象即可 package com.sunsplanter.controller;RestController public class UserController {GetMapping(value "api/login/info")public R loginInfo(Authentication a…

C++ 基础算法 双指针 数组元素的目标和

给定两个升序排序的有序数组 A 和 B &#xff0c;以及一个目标值 x 。 数组下标从 0 开始。 请你求出满足 A[i]B[j]x 的数对 (i,j) 。 数据保证有唯一解。 输入格式 第一行包含三个整数 n,m,x &#xff0c;分别表示 A 的长度&#xff0c;B 的长度以及目标值 x 。 第二行包…

使用静态CRLSP配置MPLS TE隧道

正文共&#xff1a;1591 字 13 图&#xff0c;预估阅读时间&#xff1a;4 分钟 静态CRLSP&#xff08;Constraint-based Routed Label Switched Paths&#xff0c;基于约束路由的LSP&#xff09;是指在报文经过的每一跳设备上&#xff08;包括Ingress、Transit和Egress&#xf…

使用alist连接百度网盘和阿里云盘挂载到本地磁盘

1、下载alist软件 alist软件下载地址&#xff1a;https://github.com/alist-org/alist 跳转后&#xff0c;找到对应的windows版本 2 、下载后解压&#xff0c;并启动服务 注意&#xff1a;alist的启动方式不是传统的双击启动&#xff0c;需要用命令提示符,启动服务 下载完成…

平时积累的FPGA知识点(9)

平时在FPGA群聊等积累的FPGA知识点&#xff0c;第9期&#xff1a; 31 ldpc的license是什么&#xff1f; 解释&#xff1a;Xilinx公司的Zynq UltraScale RFSoC系列芯片进行项目开发&#xff0c;在某些芯片型号中&#xff0c;自身带有SD-FEC硬核资源&#xff0c;具体查询方式&a…

Aster实现一台电脑当两台使——副屏搭配键鼠

前言&#xff1a;笔者每年回家&#xff0c;都面临着想要和小伙伴一起玩游戏&#xff0c;但小伙伴没有电脑/只有低配电脑的问题。与此同时&#xff0c;笔者自身的电脑是高配置的电脑&#xff0c;因此笔者想到&#xff0c;能否在自己的电脑上运行游戏&#xff0c;在小伙伴的电脑上…

MKS T3BI集成蝶阀说明T3B-T3PRS-232Supplement

MKS T3BI集成蝶阀说明T3B-T3PRS-232Supplement

Vue自定义指令的三个方法

目录 ​编辑 介绍 创建方法&#xff1a; min.js注册 script setup中使用 script中使用&#xff1a; 指令钩子 钩子参数 简化形式 对象字面量 在组件上使用 介绍 除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外&#xff0c;Vue 还允许你注册自定义的指令…

Codeforces Round 927 (Div. 3) LR-remainders的题解

原题描述&#xff1a; C.LR-remains 每次测试时限&#xff1a;2 秒 每次测试的内存限制&#xff1a;256 兆字节 输入&#xff1a;标准输入 输出&#xff1a;标准输出 样例1输入&#xff1a; 4 4 6 3 1 4 2 LRRL 5 1 1 1 1 1 1 LLLLL 6 8 1 2 3 4 5 6 RLLLRR 1 10000 1000…

MySQL初识——安装配置

文章目录 1. MySQL卸载2. 获取MySQL官方yum源安装包3. 安装4. 启动MySQL5. 登录6. 配置配置文件 Tips&#xff1a; 本章是Centos 7安装配置myql&#xff0c;配置操作用的是root权限 1. MySQL卸载 首先我们先查看一下系统中是否有mysql服务 ps axj | grep mysql如果有&#xf…

Vue2路由组件练习

Vue2路由组件练习 1. 演示效果 2. 代码分析 2.1. 安装 vue-router 命令&#xff1a;npm i vue-router 应用插件&#xff1a;Vue.use(VueRouter) 2.2. 创建路由文件 在 src 文件夹下&#xff0c;创建router文件夹&#xff0c;并在该文件夹创建index.js文件 2.3. 导入依赖…

K8S实战:Centos7部署Kubernetes1.20.0集群

目录 一、准备工作1.1、创建3台虚拟机1.1.1、下载虚拟机管理工具1.1.2、安装虚拟机管理工具1.1.3、下载虚Centos镜像1.1.4、创建3台虚拟机1.1.5、设置虚拟机网络环境 1.2、虚拟机基础配置&#xff08;3台虚拟机进行相同处理&#xff09;1.2.1、配置host1.2.2、关闭防火墙1.2.3、…

String字符串,FastJson常用操作方法

JSON字符串操作 1、创建配置环境 # 引入测试包testImplementation group: org.springframework.boot, name: spring-boot-starter-test, version: 2.2.6.RELEASE # 创建测试类RunWith(SpringRunner.class)SpringBootTestpublic class JsonTest {Testpublic void test(){Syste…

关于Linux中使用退格键出现^H的问题解决

关于Linux中使用退格键出现^H的问题解决 今天在Linux下执行脚本和监听端口的输入时候&#xff0c;不小心输错内容想要删除用退格键发现变成了^H&#xff0c;从网上查了资料并且实际应用了一下&#xff08;我的虚拟机是CentOS7&#xff09;。 使用ctrl退格键即可成功删除内容 …

LeetCode.105. 从前序与中序遍历序列构造二叉树

题目 105. 从前序与中序遍历序列构造二叉树 分析 这道题是告诉我们一颗二叉树的前序和中序&#xff0c;让我们根据前序和中序构造出整颗二叉树。 拿到这道题&#xff0c;我们首先要知道前序的中序又怎样的性质&#xff1a; 前序&#xff1a;【根 左 右】中序&#xff1a;…

Linux用到的命令

1 压缩文件 tar -czf wonderful.tar.gz pm 这个命令的作用就是创建一个以.tar.gz结尾的包文件&#xff0c;然后调用gzip程序将当前目录下的pm文件夹压缩到这个以.tar.gz结尾的文件里面去

【已解决】PPT无法复制内容怎么办?

想要复制PPT文件里的内容&#xff0c;却发现复制不了&#xff0c;怎么办&#xff1f; 这种情况&#xff0c;一般是PPT文件被设置了以“只读方式”打开&#xff0c;“只读方式”下的PPT无法进行编辑更改&#xff0c;也无法进行复制粘贴的操作。 想要解决这个问题&#xff0c;我…

激光雷达反光板算法总结

1 高反特征提取 首先,从雷达原始数据,提取到高反点;根据雷达的规格书提供的不同材料的强度,设定合适的阈值;;更优的方法是根据距离设定不同的阈值 2 反光板及反光柱的聚类 根据高反点是否连续进行聚类,同时结合距离及雷达的角度分辨率,计算出针对不同尺寸的反光板或反…