JavaScript进阶 | BOM caiyi 2021/8/10
一、概述 BOM = Browser Object Model
它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window
我想开个热点
BOM的构成:
window 对象是浏览器的顶级对象,它具有双重角色:
它是 JS 访问浏览器窗口的一个接口
它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法
在调用的时候可以省略 window,如 window.alert() window.prompt()
注意:window 的一个特殊属性 window.name
var num = 10 ;console .log (window .num );function fn ( ) { console .log (11 ); }window .fn ();console .log (window .name );
二、window 对象的常见事件 1. 窗口加载事件 window .onload = function ( ){}window .addEventListener ('load' ,function ( ){})document .addEventListener ('DOMContentLoaded' ,function ( ){})
==window.onload == 是窗口加载事件,当文档内容完全加载完成会触发该事件(包括图像,脚本文件,CSS文件等),就调用的处理函数
有了 window.onload 就可以把JS代码写到页面元素的上方
window.onload 是传统注册事件方式,只能写一次
如果有多个,会以最后一个 window.onload 为准
==window.addEventListener == 与 window.onload 不同的是,可以注册多次事件不会冲突和覆盖
==DOMCountentLoaded == 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等
如果页面的图片很多的话, 从用户访问到 onload 触发可能需要较长的时间
DOMContentLoaded 是DOM加载完毕,不包含图片 flash css 等就可以执行,加载速度比load更快一些
window .onload = function ( ) { var btn = document .querySelector ('button' ); btn.addEventListener ('click' , function ( ) { alert ('点击我' ); }) }window .onload = function ( ) { alert (22 ); }window .addEventListener ('load' , function ( ) { var btn = document .querySelector ('button' ); btn.addEventListener ('click' , function ( ) { alert ('点击我' ); }) })window .addEventListener ('load' , function ( ) { alert (22 ); })document .addEventListener ('DOMContentLoaded' , function ( ) { alert (33 ); })
2. 调整窗口大小事件 调整窗口大小加载事件,当触发时就调用的处理函数
我们经常利用这个事件完成响应式布局
window .onresize = function ( ) {}window .addEventListener ('resize' ,function ( ){});
==window.innerWidth ==:当前屏幕的宽度
<script > window .addEventListener ('load' , function ( ) { var div = document .querySelector ('div' ); window .addEventListener ('resize' , function ( ) { if (window .innerWidth <= 800 ) { div.style .display = 'none' ; } else { div.style .display = 'block' ; } }) }) </script > <div > </div >
三、定时器 1. setTimeout()定时器 用于设置一个定时器,该定时器在定时器到期后执行调用函数
window .setTimeout (调用函数,毫秒数);
window 在调用的时候可以省略
延时时间单位是毫秒 但是可以省略,如果省略默认的是0
页面中可能有很多的定时器,我们经常给定时器加标识符
setTimeout() 这个调用函数我们也称为回调函数 callback:普通函数是按照代码顺序直接调用,而这个函数,需要等待事件,事件到了才会去调用这个函数,因此称为回调函数
function callback ( ) { console .log ('爆炸了' ); }var timer1 = setTimeout (callback, 3000 );var timer2 = setTimeout (callback, 5000 );
2. clearTimeout()停止定时器 clearTimeout() 方法取消了先前通过调用 setTimeout() 建立的定时器
window .clearTimeout (timeoutID)
var btn = document .querySelector ('button' );var timer = setTimeout (function ( ) { console .log ('boom' ); }, 5000 ); btn.addEventListener ('click' , function ( ) { clearTimeout (timer); })
3. setInterval() 定时器 重复调用一个函数,每隔这个时间,就去调用一次回调函数
window .setInterval (回调函数,间隔毫秒数);setInterval (function ( ) { console .log ('继续输出' ); }, 1000 );
区别:
setTimeout 延时时间到了就去调用这个回调函数,只调用一次就结束了这个定时器
setInterval 每隔这个延时时间就去调用这个回调函数,会调用很多次,重复调用这个函数
4. clearInterval()停止定时器 取消了先前通过调用 setInterval() 建立的定时器
里面的参数就是定时器的标识符
<button class ="begin" > 开启定时器</button > <button class ="stop" > 停止定时器</button > <script > var begin = document .querySelector ('.begin' ); var stop = document .querySelector ('.stop' ); var timer = null ; begin.addEventListener ('click' , function ( ) { timer = setInterval (function ( ) { console .log ('ni hao ma' ); }, 1000 ); }) stop.addEventListener ('click' , function ( ) { clearInterval (timer); }) </script >
5. this 指向
全局作用域或者普通函数中 this 指向全局对象 window (注意定时器里面的this指向window)
方法调用中谁调用 this 指向谁
构造函数中 this 指向构造函数实例
console .log (this ); function fn ( ) { console .log (this ); }window .fn (); window .setTimeout (function ( ) { console .log (this ); }, 1000 ); var o = { sayHi : function ( ) { console .log (this ); } } o.sayHi ();var btn = document .querySelector ('button' ); btn.addEventListener ('click' , function ( ) { console .log (this ); })function Fun ( ) { console .log (this ); }var fun = new Fun ();
6. 案例
倒计时效果 P84
发送短信案例 P86
<button > send</button > <script > var btn = document .querySelector ('button' ) var time = 5 btn.addEventListener ('click' , function ( ) { btn.disabled = true var timer = setInterval (() => { if (time == 0 ) { clearInterval (timer) btn.disabled = false btn.innerHTML = 'send' time = 5 } else { btn.innerHTML = '还剩' + time + 's' time-- } }, 1000 ) }) </script >
四、JS执行队列 1. JS是单线程 JavaScript 语言的一大特点就是单线程,同一个时间只能做一件事
这是因为 Javascript 这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的。比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行。 应该先进行添加,之后再删除
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务
2. 同步和异步 问题引入:
console .log (1 );setTimeout (function ( ) { console .log (3 ); },1000 );console .log (2 );console .log (1 );setTimeout (function ( ) { console .log (3 ); },0 );console .log (2 );
利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,于是,JS 中出现了同步和异步:
同步:前一个任务结束后再执行后一个任务
异步:在做这件事的同时,你还可以去处理其他事情
3. 执行队列 同步任务 :同步任务都在主线程上执行,形成一个 执行栈
异步任务 :JS中的异步是通过 回调函数 实现的,异步任务相关回调函数添加到 任务队列 中
异步任务有以下三种类型:
普通事件,如 click, resize 等
资源加载,如 load, error 等
定时器,包括 setInterval, setTimeout 等
执行过程详解 :
先执行 执行栈 中的同步任务
异步任务(回调函数)放入 任务队列 中
一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行
同步任务放在执行栈中执行,异步任务由异步进程处理放到任务队列中,执行栈中的任务执行完毕会去任务队列中查看是否有异步任务执行,由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为 事件循环
五、location对象 location 属性用于获取或者设置窗体的url,并且可以解析url
因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。
1. URL ==统一资源定位符==(uniform resouce locator):是互联网上标准资源的地址,互联网上的每个文件都有一个唯一的 URL,它包含的信息指出 文件的位置 以及 浏览器应该怎么处理它 。
url的一般格式 :
protocol:// host[:port]/path/ [?query] http:// www.itcast.cn/index.html?name=andy&age=18
url组成
说明
protocol
通信协议 常用的http,ftp,maito等
host
主机(域名) www.itheima.com
port
端口号,省略时为默认端口号80
path
路径,由’/‘符号隔开,目录或文件地址
query
参数,以键值对的形式,通过&符号分隔开来
fragment
片段,#后面内容,常见于链接、锚点
2. location对象属性 对象属性 返回值 location.href 获取或者设置整个URL location.host 返回主机(域名)www.baidu .com location.port 返回端口号,如果未写返回空字符串 location.pathname 返回路径 location.search 返回参数 location.hash 返回片段 #后面内容常见于链接 锚点
重点记住: href,search
小案例:5s之后跳转页面
<div > </div > <script > var div = document .querySelector ('div' ); var timer = 5 ; setInterval (function ( ) { if (timer == 0 ) { location.href = 'http://www.itcast.cn' ; } else { div.innerHTML = '您将在' + timer + '秒钟之后跳转到首页' ; timer--; } }, 1000 ); </script >
3. 获取URL参数 主要练习数据在不同页面中的传递
我们简单写一个登录框,点击登录跳转到 index.html
<body > <form action ="index.html" > 用户名: <input type ="text" name ="uname" > <input type ="submit" value ="登录" > </form > </body >
接下来我们写 index.html
<body > <div > </div > <script > console .log (location.search ); var params = location.search .substr (1 ); console .log (params); var arr = params.split ('=' ); console .log (arr); var div = document .querySelector ('div' ); div.innerHTML = arr[1 ] + '欢迎您' ; </script > </body >
这样我们就能获取到路径上的URL参数
4. location对象方法 对象方法 返回值location .assign() 跟href一样,可以跳转页面(也称为重定向页面),可以记录历史,有后退功能location .replace() 替换当前页面,因为不记录历史,所以不能后退页面location .reload() 重新加载页面,相当于刷新按钮或者 f5 ,如果参数为true 强制刷新 ctrl+f5
<button > 点击</button > <script > var btn = document .querySelector ('button' ); btn.addEventListener ('click' , function ( ) { location.assign ('http://www.itcast.cn' ); location.replace ('http://www.itcast.cn' ); location.reload (true ); }) </script >
六、navigator对象 avigator 对象包含有关浏览器的信息,它有很多属性
我们常用的是 ==userAgent== , 该属性可以返回由客户机发送服务器的 ==user-agent == 头部的值
下面 JavaScript 代码可以判断用户是用哪个终端打开页面的,如果是用 PC 打开的,就跳转到 PC 端的页面,如果是用手机打开的,就跳转到手机端页面
if ((navigator.userAgent .match (/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i ))) { window .location .href = "" ; } else { window .location .href = "" ; }
七、history对象 window 给我们提供了一个 history 对象,与浏览器历史记录进行交互
该对象包含用户(在浏览器窗口中)访问过的 URL
history对象方法
作用
back()
可以后退功能
forward()
前进功能
go(参数)
前进后退功能,参数如果是 1 前进1个页面 如果是 -1 后退1个页面
<a href ="list.html" > 点击我去往列表页</a > <button > 前进</button > <script > var btn = document .querySelector ('button' ); btn.addEventListener ('click' , function ( ) { history.go (1 ); }) </script >
JavaScript进阶 | DOM caiyi 2021/8/2
一、DOM简介 文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口
W3C 已经定义了一系列的 DOM 接口,通过这些 DOM 接口可以改变网页的内容、结构和样式 。
dom树 :
文档:一个页面就是一个文档,DOM中使用doucument来表示
元素:页面中的所有标签都是元素,DOM中使用 element 表示
节点:网页中的所有内容都是节点(标签,属性,文本,注释等),DOM中使用node表示
DOM 把以上内容都看做是对象
二、获取元素 1. 根据ID获取 可以获取带ID的元素对象
doucument.getElementByld ('id名' )
<div id ="time" > 2021-8-3</div > <script > var timer = document .getElementById ('time' ); console .log (timer); console .dir (timer); </script >
2. 根据标签名获取 根据标签名获取,返回带有指定标签名的对象的集合
doucument.getElementsByTagName ('标签名' );
<ul > <li > 知否知否</li > <li > 知否知否</li > <li > 知否知否</li > </ul > <script > var lis = document .getElementsByTagName ('li' ); console .log (lis); console .log (lis[0 ]); for (var i = 0 ; i < lis.length ; i++) { console .log (lis[i]); } </script >
3. 根据父元素+标签名获取 还可以根据标签名获取某个元素(父元素)内部所有指定标签名的子元素,获取的时候不包括父元素自己
element.getElementsByTagName ('标签名' ) ol.getElementsByTagName ('li' );
<script > var ol = document .getElementById ('ol' ); console .log (ol[0 ].getElementsByTagName ('li' )); </script >
注意:父元素必须是单个对象(必须指明是哪一个元素对象),不能是伪数组,会报错
4. 通过H5新增方法获取 注意html5是ie9以上的版本才支持的
document .getElementsByClassName ('类名' );
根据指定选择器(.类选择器,#id选择器,标签选择器)return第一个元素对象
document .querySelector ('选择器' );
根据指定选择器(.类选择器,#id选择器,标签选择器)retrun所有元素对象合集,伪数组
document .querySelectorAll ('选择器' );
用法举例:
<div class ="box" > </div > <div class ="box" > </div > <div id ="nav" > <ul > <li > 首页</li > <li > 产品</li > </ul > </div > <script > var boxs = document .getElementsByClassName ('box' ); console .log (boxs); var firstBox = document .querySelector ('.box' ); console .log (firstBox); var nav = document .querySelector ('#nav' ); console .log (nav); var li = document .querySelector ('li' ); console .log (li); var allBox = document .querySelectorAll ('.box' ); console .log (allBox); var lis = document .querySelectorAll ('li' ); console .log (lis); </script >
5. 获取body和html元素对象 document .body ; document .documentElement ;
三、事件基础 JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。
1. 事件三要素 事件源:事件被触发的对象
事件类型:如何触发,什么事件,比如是鼠标点击,还是鼠标经过,还是键盘按下
事件处理程序:通过一个函数赋值的方式完成
<script > var btn = document .getElementById ('btn' ); btn.onclick = function ( ) { alert ('吃麻辣鸡' ); } </script >
2. 执行事件的步骤
获取事件源
注册事件(绑定事件)
添加事件处理程序(采取函数赋值形式)
<div > 1234</div > <script > var div = document .querySelector ('div' ); div.onclick = function ( ) { console .log ('我被选中了' ); } </script >
鼠标事件类型:
鼠标事件
触发条件
onclick
鼠标点击左键触发
onmouseover
鼠标经过触发
onmouseout
鼠标离开触发
onfocus
获得鼠标焦点触发
onblur
失去鼠标焦点触发
onmousemove
鼠标移动触发
onmouseup
鼠标弹起触发
onmousedown
鼠标按下触发
四、操作元素 JavaScript 的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容 、属性等。注意以下都是属性
1. 改变元素的内容 从起始位置到终止位置的内容,不识别html标签,去除空格和换行,非标准
element.innerText = 'str'
起始位置到终止位置的全部内容,识别HTML标签,保留空格和换行,W3C标准
这两个属性都是可读写的 可以获取元素里面的内容
innerText 和 innerHTML 只能修改普通盒子,比如div标签里面的内容
<div > </div > <p > 我是文字 <span > 123</span > </p > <script > var div = document .querySelector ('div' ); div.innerText = '<strong>今天是:2021</strong>' ; div.innerHTML = '<strong>今天是:2021</strong>' ; var p = document .querySelector ('p' ); console .log (p.innerText ); console .log (p.innerHTML ); </script >
2. 改变元素属性 修改img属性:
img.src = 'xxx' ; img.title = 'xxx' ;
通过点击不同按钮切换图片举例:
<button id ="ldh" > 刘德华</button > <button id ="zxy" > 张学友</button > <img src ="images/ldh.jpg" title ="刘德华" > <script > var ldh = document .getElementById ('ldh' ); var zxy = document .getElementById ('zxy' ); var img = document .querySelector ('img' ); zxy.onclick = function ( ) { img.src = 'images/zxy.jpg' ; } ldh.onclick = function ( ) { img.src = 'images/ldh.jpg' ; } </script >
修改表单属性:
input.value = 'xxx' ; input.type = 'xxx' ; input.checked = 'xxx' ; input.selected = true / false ; input.disabled = true / false ;
btn.onClick = function ( ) { input.value = 'clicked' ; this .disabled = true ; }
3. 改变样式属性 我们可以通过 JS 修改元素的大小、颜色、位置等样式
div.style .backgroundColor = 'pink' ; div.style .width = '250px' ; box.style .display = 'none' ;
两种操作方法改变样式属性对比举例:
<sytle > .change { background-color: purple; color: #fff; font-size: 25px; }</sytle > <div class ="first" > 文本</div > <script > var test = document .querySelector ('div' ); test.onclick = function ( ) { this .style .backgroundColor = 'purple' ; this .style .color = '#fff' ; this .style .fontSize = '25px' ; this .className = 'change' ; this .className = 'first change' ; } </script >
注意:
JS里面的样式采取驼峰命名法,比如 fontSize ,backgroundColor
JS 修改 style 样式操作 ,产生的是 行内样式 ,CSS权重比较高
如果样式修改较多,可以采取操作类名方式更改元素样式
class 因为是个保留字,因此使用 className 来操作元素类名属性
className 会直接更改元素的类名,会覆盖原先的类名
4. 小总结
5. 排他思想 如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环的排他思想算法
首先先排除其他人,然后才设置自己的样式 这种排除其他人的思想我们成为排他思想
实现:
<body > <button > 按钮1</button > <button > 按钮2</button > <button > 按钮3</button > <button > 按钮4</button > <button > 按钮5</button > <script > var btns = document .getElementsByTagName ('button' ); for (var i = 0 ; i < btns.length ; i++) { btns[i].onclick = function ( ) { for (var i = 0 ; i < btns.length ; i++) { btns[i].style .backgroundColor = '' ; } this .style .backgroundColor = 'pink' ; } } </script > </body >
6. 自定义属性
获取属性值
element.属性; element.getAttribute ('属性' );
设置属性值
element.属性 = '值' ; element.setAttribute ('属性' ,'值' );
移除属性
element.removeAttribute ('属性' );
<body > <div id ="demo" index ="1" class ="nav" > </div > <script > var div = document .querySelector ('div' ); console .log (div.id ); console .log (div.getAttribute ('id' )); console .log (div.getAttribute ('index' )); div.id = 'test' ; div.className = 'navs' ; div.setAttribute ('index' , 2 ); div.setAttribute ('class' , 'footer' ); div.removeAttribute ('index' ); </script > </body >
7. H5自定义属性 自定义属性目的:保存并保存数据,有些数据可以保存到页面中而不用保存到数据库中
有些自定义属性很容易引起歧义,不容易判断到底是内置属性还是自定义的,所以H5有了规定
综合举例:
<body > <div data-index ="2" data-list-name ="andy" > </div > <script > var div = document .querySelector ('div' ); div.setAttribute ('data-time' , 20 ); console .log (div.getAttribute ('data-index' )); console .log (div.getAttribute ('data-list-name' )); 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 >
8. 案例
仿京东显示隐藏密码明文案例 P17
仿淘宝关闭二维码 P20
循环精灵图 P21
显示隐藏文本框内容 P22
密码验证信息 P24
百度换肤效果 P27
表格隔行变色 P28
表单全选取消全选 P29
tab栏切换 P33
五、节点操作 获取元素通常使用两种方式:
1.利用DOM提供的方法获取元素
2.利用节点层级关系获取元素
document.getElementById()
利用父子兄节点关系获取元素
document.getElementsByTagName()
逻辑性强,但是兼容性较差
document.querySelector()
逻辑性不强,繁琐
这两种方式都可以获取元素节点,我们后面都会使用,但是节点操作更简单
1. 节点概述 网页中的所有内容都是节点(元素、属性、文本等),在DOM 中,节点使用 node 来表示
HTML DOM 树中的所有节点均可通过 JavaScript 进行访问,均可被修改,也可以创建或删除。
节点至少有三个基本属性:
- node.nodeType(元素为nodeType1、属性为2、文本为3)- node.nodeName- node.nodeValue
我们在实际开发中,节点操作主要操作的是元素节点
利用 DOM 树可以把节点划分为不同的层级关系,常见的是父子兄层级关系
2. 父级节点
返回某节点最近的一个父结点
如果指定的节点没有父结点则返回null
<div class ="box" > <span class ="son" > ×</span > </div > <script > var child = document .querySelector ('.son' ); console .log (child.parentNode ); </script >
3. 子结点 获取所有子节点
Node .childNodes Node .children
关于 Node.childNodes 的说明:
Node.childNodes 返回包含指定节点的子节点的集合,即时更新
返回值包含了所有的子结点,包括元素节点,文本节点等
如果只想要获得里面的元素节点,则需要判断nodeType,所以一般不提倡使用 childNodes
关于 Node.children 的说明:
parentNode.children
是一个只读属性,返回所有的子元素节点
它只返回子元素节点,其余节点不返回 (这个是我们重点掌握的 )
虽然 children 是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用
var ul = document .querySelector ('ul' );console .log (ul.childNodes ); console .log (ul.children );
第一个和最后一个子节点:
Node .firstChild Node .lastChild Node .firstElementChild Node .lastElementChild
解决方案:
firstChild 和 lastChild 包含其他节点,操作不方便,而 firstElementChild 和 lastElementChild 又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?
Node .chilren [0 ] Node .chilren [Node .chilren .length - 1 ]
案例:下拉菜单 P41
4. 兄弟节点 获取兄弟节点
node.nextSibling node.previousSibling node.nextElementSibling node.previousElementSibling
举例:
<body > <div > 我是div</div > <span > 我是span</span > <script > var div = document .querySelector ('div' ); console .log (div.nextSibling ); console .log (div.previousSibling ); console .log (div.nextElementSibling ); console .log (div.previousElementSibling ); </script > </body >
解决方案:自己封装一个兼容性的函数
function getNextElementSibling (element ) { var el = element; while (el = el.nextSibling ) { if (el.nodeType === 1 ){ return el; } } return null ; }
5. 创建节点 var newNode = document .createElement ('tagName' );
添加节点
node.appendChild (newNode) node.insertBefore (newNode,指定元素)
我们想要页面添加一个新的元素分两步: 1. 创建元素 2. 添加元素
<body > <ul > <li > 123</li > </ul > <script > var ul = document .querySelector ('ul' ); var li = document .createElement ('li' ); ul.appendChild (li); var lili = document .createElement ('li' ); ul.insertBefore (lili, ul.children [0 ]); </script > </body >
删除节点
复制节点
node.cloneNode() 方法返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点
括号参数为空或者为 false ,是浅拷贝 ,只复制节点本身,不复制里面的子节点
括号参数为 true ,是深拷贝 ,会复制节点本身,以及里面所有的子节点
案例:简单版发布留言 删除留言 P44
<textarea name ="" id ="" > 123</textarea > <button > submit</button > <ul > </ul > <script > var btn = document .querySelector ("button" ); var text = document .querySelector ("textarea" ); var ul = document .querySelector ("ul" ); btn.onclick = function fun ( ) { if (text.value == "" ) { alert ("none" ); } else { var newli = document .createElement ("li" ); ul.appendChild (newli); newli.innerHTML = text.value + " <a href='javascript::'>delete</a>" ; var as = document .querySelectorAll ("a" ); for (var i = 0 ; i < as .length ; i++) { as [i].onclick = function fun ( ) { ul.removeChild (this .parentNode ); }; } } }; </script >
案例:动态生成表格 P48
6. 了解 三种动态创建元素的方法 :
- doucument.write () - element.innerHTML - document .createElement ()
doucument.write 和 innerHTML 的区别:
document.write()
是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
innerHTML
是将内容写入某个 DOM 节点,不会导致页面全部重绘
createElement 和 innerHTML 区别:
innerHTML
创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
createElement()
创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下, innerHTML 只要采取数组形式,效率都要比 createElement 高
经典面试题 :
createElement 和 innerHTML 哪个创建元素的效率更高?👆
六、DOM 核心(半期总结) 对于DOM操作,我们主要针对子元素的操作,主要有
创建、增、删、改、查、属性操作、时间操作
1. 创建
document.write
innerHTML
createElement
2. 增加
appendChild
insertBefore
3. 删除
removeChild
4. 修改 主要修改dom的元素属性,dom元素的内容、属性、表单的值等
修改元素属性:src、href、title 等
修改普通元素内容:innerHTML、innerText
修改表单元素:value、type、disabled
修改元素样式:style、className
5. 查找 主要获取查询dom的元素
DOM提供的API方法:getElementById、getElementsByTagName
H5提供的新方法:querySelector、querySelectorAll (提倡)
利用节点操作获取元素:parentNode、children、previousElementSibling、nextElementSibling
6. 属性操作 主要针对于自定义属性
setAttribute:设置dom的属性值
getAttribute:得到dom的属性值
removeAttribute:移除属性
七、事件高级 1. 注册事件(绑定事件) 注册事件有两种方式:传统方式和方法监听注册方式
(1) 传统方式:
利用on开头的事件 ,特点是注册事件的唯一性,同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
btn.onclick = function () {}
(2) 方法监听注册方式:
w3c 标准推荐方式,IE9 之前的 IE 不支持此方法,可使用 attachEvent() 代替
同一个元素同一个事件 ==可以注册多个监听器==,按注册顺序依次执行
eventTarget.addEventListener (type,listener[,useCapture])
type
: 事件类型字符串,click,mouseover,这里不要带on
listener
:事件处理函数,事件发生时,会调用该监听函数
useCapture
:可选参数,是一个布尔值,默认是 false
eventTarget.attachEvent(eventNameWithOn ,callback )
eventNameWithOn
:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on
callback
: 事件处理函数,当目标触发事件时回调函数被调用
<button > 传统注册事件</button > <button > 方法监听注册事件</button > <button > ie9 attachEvent</button > <script > var btns = document .querySelectorAll ('button' ); btns[0 ].onclick = function ( ) { alert ('hi' ); } btns[1 ].addEventListener ('click' , function ( ) { alert (22 ); }) btns[2 ].attachEvent ('onclick' , function ( ) { alert (11 ); }) </script >
(3)注册事件兼容性解决方案 :
首先照顾大多数浏览器,再处理特殊浏览器
function addEventListener (element, eventName, fn ) { if (element.addEventListener ) { element.addEventListener (eventName, fn); } else if (element.attachEvent ) { element.attachEvent ('on' + eventName, fn); } else { element['on' + eventName] = fn; }
2. 删除事件(解绑事件) (1) 传统方式删除事件
eventTarget.onclick = null ;
(2) 方法监听注册方式
eventTarget.removeEventListener(type ,listener [,useCapture ]) ;
type
:事件类型字符串,比如 click, mouseon, 不要带on
listener
:注意这里不能用匿名函数的方法,调用不需要加小括号
useCapture
:可选参数,是一个布尔值,默认是 false
eventTarget.detachEvent(eventNameWithOn ,callback ) ;
eventNameWithOn
:事件类型字符串,比如 onclick, onmouseover,要带 on
callback
: 不能用匿名函数的方法,调用不需要加小括号
(2) 删除事件兼容性解决方案
function removeEventListener (element, eventName, fn ) { if (element.removeEventListener ) { element.removeEventListener (eventName, fn); } else if (element.detachEvent ) { element.detachEvent ('on' + eventName, fn); } else { element['on' + eventName] = null ; }
举例:点击一次就不再弹出对话框的实现
<div > 1</div > <div > 2</div > <div > 3</div > <script > var divs = document .querySelectorAll ('div' ); divs[0 ].onclick = function ( ) { alert (11 ); divs[0 ].onclick = null ; } divs[1 ].addEventListener ('click' ,fn); function fn ( ){ alert (22 ); divs[1 ].removeEventListener ('click' ,fn); } divs[2 ].attachEvent ('onclick' ,fn1); function fn1 ( ) { alert (33 ); divs[2 ].detachEvent ('onclick' ,fn1); } </script >
3. DOM事件流 事件流描述的是从页面中接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程 即DOM事件流
dom事件流分成三个阶段:
事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收
当前目标阶段
事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点
注意:
JS 代码中只能执行捕获或者冒泡其中的一个阶段
onclick 和 attachEvent 只能得到冒泡阶段
如果 addEventListener 第三个参数是 true 那么则处于捕获阶段,false 处于冒泡阶段
有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
4. 事件对象 event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态
事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
eventTarget.onclick = function (event ) { } eventTarget.addEventListen \er ('click' , function (event ) { })
事件对象也有兼容性问题:ie678 通过 window.event
兼容性的写法 e = e || window.event;
事件对象的常见属性和方法
e.target 返回触发事件的对象 标准 e.srcElement 返回触发事件的对象 非标准 ie6-8 使用 e.type 返回事件的类型 比如click mouseover 不带on e.cancelBubble 该属性阻止冒泡,非标准,ie6-8 使用 e.returnValue 该属性阻止默认行为 非标准,ie6-8 使用 e.preventDefault () 该方法阻止默认行为 标准 比如不让链接跳转 e.stopPropagation () 阻止冒泡 标准
e.target 和 this 的区别
e.target 返回的是触发事件的对象(元素),this 返回的是绑定事件的对象(元素)
<ul > <li > 123</li > <li > 123</li > <li > 123</li > </ul > <script > var ul = document .querySelector ('ul' ); ul.addEventListener ('click' , function (e ) { console .log (this ); console .log (e.target ); }) </script >
5. 事件对象阻止默认行为 链接不跳转,或者让提交按钮不提交
<a href ="http://www.baidu.com" > 百度</a > <script > var a = document .querySelector ('a' ); a.addEventListener ('click' , function (e ) { e.preventDefault (); }) a.onclick = function (e ) { e.preventDefault (); e.returnValue ; return false ; } </script >
6. 阻止事件冒泡 :star:面试中经常问到的问题
事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点
e.stopPropagation (); e.cancelBubble = true ;
var son = document .querySelector ('.son' ); son.addEventListener ('click' , function (e ) { alert ('son' ); e.stopPropagation (); e.cancelBubble = true ; }, false );
7. 事件委托 :star:事件委托的原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
作用:只操作了一次DOM,提高了程序性能
以下案例:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器。
<ul > <li > 知否知否,点我应有弹框在手!</li > <li > 知否知否,点我应有弹框在手!</li > <li > 知否知否,点我应有弹框在手!</li > <li > 知否知否,点我应有弹框在手!</li > <li > 知否知否,点我应有弹框在手!</li > </ul > <script > var ul = document .querySelector ('ul' ); ul.addEventListener ('click' , function (e ) { alert ('知否知否' ); e.target .style .backgroundColor = 'pink' ; }) </script >
8. 常用的鼠标事件
鼠标事件
触发条件
onclick
鼠标点击左键触发
onmouseover
鼠标经过触发
onmouseout
鼠标离开触发
onfocus
获得鼠标焦点触发
onblur
失去鼠标焦点触发
onmousemove
鼠标移动触发
onmouseup
鼠标弹起触发
onmousedown
鼠标按下触发
contextmenu
主要用于取消默认的上下文菜单
selectstart
用于禁止鼠标选中
禁止鼠标右键与鼠标选中
<h1 > 我是一段不愿意分享的文字</h1 > <script > document .addEventListener ('contextmenu' , function (e ) { e.preventDefault (); }) document .addEventListener ('selectstart' , function (e ) { e.preventDefault (); }) </script >
鼠标事件对象 :
鼠标事件对象
说明
e.clientX
鼠标相对于浏览器窗口可视区 的X坐标
e.clientY
鼠标相对于浏览器窗口可视区 的Y坐标
e.pageX(重点)
鼠标相对于文档页面 的X坐标 IE9+ 支持
e.pageY(重点)
鼠标相对于文档页面 的Y坐标 IE9+ 支持
e.screenX
鼠标相对于电脑屏幕 的X坐标
e.screenY
鼠标相对于电脑屏幕 的Y坐标
document .addEventListener ('click' , function (e ) { console .log (e.clientX ); console .log (e.clientY ); console .log (e.pageX ); console .log (e.pageY ); console .log (e.screenX ); console .log (e.screenY ); })
案例:跟随鼠标移动的图片
<head > <style > img { height : 140px ; width : 120px ; position : absolute; } </style > </head > <body > <img src ="C:\Users\lenovo\Pictures\IMG_3554.PNG" /> <script > var pic = document .querySelector ('img' ) document .addEventListener ('mousemove' , function (e ) { var x = e.pageX var y = e.pageY pic.style .left = x - 70 + 'px' pic.style .top = y - 60 + 'px' }) </script > </body >
9. 常用的键盘事件
键盘事件
触发条件
onkeyup
某个键盘按键被松开时触发
onkeydown
某个键盘按键被按下时触发
onkeypress
某个键盘按键被按下时触发,但是它不识别功能键,比如 ctrl shift 左右箭头
document .addEventListener ('keyup' , function ( ) { console .log ('我弹起了' ); })document .addEventListener ('keypress' , function ( ) { console .log ('我按下了press' ); })document .addEventListener ('keydown' , function ( ) { console .log ('我按下了down' ); })
三个事件的执行顺序 keydown —> keypress —> keyup
键盘事件对象:
键盘事件对象
说明
keyCode
返回该键值的ASCII值
keyup 和 keydown 事件不区分字母大小写,a 和 A 得到的都是65
keypress 事件区分字母大小写,a 97,A 65
document .addEventListener ('keyup' , function (e ) { console .log ('up:' + e.keyCode ); })document .addEventListener ('keypress' , function (e ) { console .log ('press:' + e.keyCode ); })
案例1:按键focus输入框
search.focus()
案例2:输入数字显示大字
con.style.display = ‘none’;
con.style.display = ‘block’;