DOM事件基础 获取元素 1.获取元素对象的方法
1 2 3 4 5 6 7 8 9 10 11 document .getElementById()document .getElementsByTagName() document .getElementByClassName() document .querySelector('选择器' ) document .querySelectorAll()
2.获取特殊元素
1 2 3 4 var eleBody = document .body;var eleHtml = document .documentElement;
事件基础
事件是由 事件源、事件类型、事件处理程序 组成,称为事件三要素
1 2 3 4 5 6 7 8 9 10 var btn = document .querySelector('#btn' )btn.onclick btn.onclick = function ( ) { console .log('被点击了' ) }
常见鼠标事件
鼠标事件
触发条件
onclick
鼠标点击左键触发
onmouseover
鼠标经过触发
onmouseout
鼠标离开触发
onfocus
获取鼠标焦点触发
onblur
失去鼠标焦点触发
onmousemove
鼠标移动触发
onmouseup
鼠标弹起触发
onmousedown
鼠标按下触发
操作元素 1.改变元素内容
innerText
:IE发起,非标准。去除换行和空格
innerHTML
:能渲染 HTML 标签,保留换行和空格(W3C标准)
2.表单元素的属性操作
type、value、checked、selected、disabled
3.样式属性操作
注意:
JS 里面的样式采用驼峰命名法
JS 修改 style 样式操作,产生的是行内样式,css 权重比较高
4.自定义属性操作
自定义属性的目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存数据库中。
1 2 3 4 5 6 <div id ="demo" > </div > <script > var div = document .querySelector('div' ) console .log(div.id) var id = div.getAttribute('id' ) </script >
设置属性值
1 2 div.id = 'demo2' div.setAttribute('id' ,'demo2' )
规范
element.属性值 = '值'
:设置内置属性
element.setAttribute('id','demo2')
:设置自定义属性
移除属性
div.removeAttribute('data-index')
自定义属性规范
H5规定自定义属性data-
开头作为属性名并且赋值
H5新增获取自定义属性的方法
1 2 3 4 5 6 7 8 9 10 11 <div data-index ="2" data-list-name ="simple" > </div > <script > var div = document .querySelector('div' ) console .log(div.dataset.index) console .log(div.dataset['index' ]) div.dataset.listName div.dataset['listName' ] </script >
dataset
是 规范自定义属性的集合,data-
开头的都存在这个集合里面
console.log(div.dataset.index) console.log(div.dataset['index'])
节点操作
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性
元素节点 nodeType = 1
属性节点 nodeType = 1
文本节点 nodeType = 1(文本节点包含文字、空格、换行等)
父节点 和 子节点操作
1 2 3 4 5 6 7 8 9 10 11 <div class ="box" > <span class ="erweima" > X</span > </div > <script > var erweima = document .querySelector('.erweima' ) var box = document .querySelector('.box' ) var box = erweima.parentNode </script >
1 2 3 4 5 6 7 8 9 10 <ul > <li > </li > <li > </li > <li > </li > </ul > <script > var ul = document .querySelector('ul' ) var lis = ul.childNodes </script >
获取子节点集合包含 元素节点 文本节点 等等。需要专为处理才能获取元素节点,因此不推荐使用 childNodes 获取子节点
通过非标准方法 : children
ul.children 获取是就是子节点元素,虽然不标准,但是得到浏览器的支持
获取第一个元素节点和最后一个元素节点
1 2 3 4 5 6 7 8 parentNode.firstChild parentNode.lastChild parentNode.firstElementChild parentNpde.lastElementChild parentNode.children[0 ] parentNode.children[parentNode.children.length - 1 ]
兄弟节点
1 2 3 4 5 6 7 var div = document .querySelector('div' )node.nextSibling node.previousSibling
添加节点
document.createElement('li')
创建节点元素
node.appendChild(child)
将一个节点添加到指定父节点的子节点列表末尾。类似于 css 里面的 before伪元素
node.insertBefore(child,指定元素)
:指定元素是指子元素的哪一个,用节点选择
将一个节点添加到指定父节点的子节点列表末尾。类似于 css 里面的 after 伪元素
node.insertBefore(child,node.children[0])
插入到第一个上面
删除节点
node.removeChild(node.children)
克隆节点
node.cloneNode()
括号为空或者false 是浅拷贝,只复制标签
node.cloneNode(true)
复制内容
动态生成表格案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > table { border-collapse : collapse; width : 500px ; margin : 100px auto; text-align : center; } th ,td { border : 1px solid #333 ; width : 200px ; } 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 > var data = [{ name : '李四' , subject : 'javascript' , score : 98 }, { name : '张三' , subject : 'javascript' , score : 90 }, { name : '老刘' , subject : 'javascript' , score : 92 }, { name : '李逵' , subject : 'javascript' , score : 45 }] var tbody = document .querySelector('tbody' ) data.forEach( obj => { var tr = document .createElement('tr' ) tbody.appendChild(tr) for (var i in obj){ var td = document .createElement('td' ) td.innerHTML = obj[i] tr.appendChild(td) } var td = document .createElement('td' ) td.innerHTML = '<a href="javascript:;">删除</a>' tr.appendChild(td) }); var a = document .querySelectorAll('a' ) for (var i=0 ;i<a.length;i++){ a[i].onclick = function ( ) { tbody.removeChild(this .parentNode.parentNode) } } </script > </body > </html >
三种创建元素方式的区别
document.write()
element.innerHTML
document.createElement()
事件高级 注册事件(绑定事件)
给元素添加事件,称为注册事件或者绑定事件
注册事件有两种方式:传统方式和方法监听注册方式
1.方法监听注册方式
1 2 3 btn.addEventListener('click' ,function ( ) { })
删除事件(解绑事件) 1 2 3 4 5 6 btn.onclick = null ; eventTarget.removeEventListener(type,listener[,useCapture]) btn.removeEventListener('click' ,fn)
Dom事件流
事件流描述的是从页面中接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 var son = document .querySelector('#son' )var father = document .querySelector('#father' )son.addEventListener('click' ,function ( ) { console .log(1111 ) },true ) father.addEventListener('click' ,function ( ) { console .log(2222 ) },true ) son.addEventListener('click' ,function ( ) { console .log(1111 ) },false ) father.addEventListener('click' ,function ( ) { console .log(2222 ) },false )
事件对象 侦听函数有一个形参 event
里面有很多事件属性
1 2 3 4 5 6 div.onclick = function (event ) { console .log(event) } div.addEventListener('click' ,function (event ) { })
e.target
是触发对象
this
是绑定对象,两者有可能一样,但不完全一样
阻止默认行为
1 2 3 4 var a = document .querySelector('a' ); a.addEventListener('click' ,function (e ) { e.preventDefault(); })
阻止事件冒泡 事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点
事件冒泡本身的特性,会带来坏处,也会带来好处,需要灵活处理
阻止事件冒泡
标准写法:利用事件对象里面的 stopPropagation()
方法
事件委托(代理、委派) 事件委托原理: 不是每一个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <ul > <li > 1</li > <li > 2</li > <li > 3</li > <li > 4</li > <li > 5</li > <li > 6</li > <li > 7</li > <li > 8</li > <li > 9</li > <li > 10</li > </ul > <script > var ul = document .querySelector('ul' ) ul.addEventListener('click' ,function (e ) { e.target.onclick = function ( ) { ul.removeChild(this ) } },true ) </script >
常用鼠标事件 1.禁用右键菜单
1 2 3 document .addEventListener('contextmenu' ,function (e ) { e.preventDefault(); })
2.禁止选中文字
1 2 3 document .addEventListener('selectstart' ,function (e ) { e.preventDefault(); })
案例:跟随鼠标移动的天使
鼠标不断的移动,使用鼠标移动事件:mouesmove
在页面中移动,给document注册事件
图片要移动距离,而且不占位置,使用绝对定位
核心原理:每次鼠标移动,我们都会获得最新的鼠标坐标,把这个X和Y坐标作为图片的top和left值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function mouseRouser ( ) { var body = document .body; var img = document .createElement("img" ); img.style.position = "absolute" ; img.style.pointerEvents = "none" ; img.src = "https://cdn.jsdelivr.net/gh/SimpleLifecst/simple@main//angel.gif" ; body.appendChild(img); document .addEventListener("mousemove" , function (e ) { var x = e.pageX; var y = e.pageY; img.style.top = y + "px" ; img.style.left = x + "px" ; }); } mouseRouser();
常用键盘事件
键盘事件
触发条件
onkeyup
某个键盘按键被松开时触发
onkeydown
某个键盘按键被按下时触发(会一直触发)
onkeypress
某个键盘按键被按下时触发 但是不识别功能键 比如 ctrl shift 箭头等
键盘事件对象
1 2 3 document .addEventListener('keyup' ,function (e ) { console .log(e.keyCode) })
keyup 和 keydown 不区分大小写 a A 都是 65
keypress 事件区分大小写
BOM浏览器对象模型 BOM 概述
BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器宽口进行交互的对象,其核心对象就是 window
window对象是浏览器的顶级对象
,它具有双重角色
它是 JS 访问浏览器窗口的一个接口
它是一个全局对象,定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。在调用的时候可以省略 window,前面学习的对话框都属于 window对象方法,如 alert()、prompt()
window 对象的常见事件 1.窗口加载事件
1 2 window .onload = function ( ) {} window .addEventListener('load' ,function ( ) {})
window.onload
是窗口加载事件,当文档内容完全加载会触发该事件(包括图像、脚本文件、CSS文件等),就调用的处理函数
1 2 document .addEventListener('DOMContentLoaded' ,function ( ) {})
2.调整窗口大小事件
1 2 3 4 5 6 window .onresize = function ( ) {}window .addEventListener('resize' ,function ( ) {})
定时器 window 对象给我们提供了2个非常好用的方法-定时器
setTimeout()
执行一次
setInterval()
每隔一定时间执行一次
清除定时器
1 2 3 4 5 6 7 8 9 10 11 var timer = setTimeout (function ( ) { console .log('ok' ) },2000 ) clearTimeout (timer) var timer2 = setInterval (function ( ) { console .log('ok' ) },2000 ) clearInterval (timer2)
this指向问题
在全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window),指向的是调用者
1 2 3 4 5 6 var o = { sayHi :function ( ) { console .log(this ) } }
1 2 3 4 5 function Fun ( ) { console .log(this ) } var fun = new Fun()
JS 执行机制 JS 执行机制是单线程的
1.先执行执行栈中的同步任务;2.异步任务(回调函数)放入任务队列中;3.一旦执行栈中所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行
1.异步任务
JS异步是通过回调函数实现的
一般,异步任务有以下三种类型
普通事件、click、resize等
资源加载,如load、error等
定时器,包括 setInterval、setTimeout
异步任务相关回调函数添加到任务队列中(任务队列也称消息队列)
2.事件循环
由于主线程不断的重复获取任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环(event loop)
location 对象
window 对象给我们提供了一个location属性用于获取或设置窗体的URL,并且可以用于解析URL。因为这个属性返回的是一个对象,所以我们将这个属性也称为location对象
1 2 3 4 5 6 7 var params = location.search.substr(1 )var arr = params.split('=' )console .log(arr)
navigator 对象 navigator
对象包含有关浏览器的信息,它有很多属性,我们常用的就是 userAgent
,该属性可以返回由客户端发送服务器的 user-agent
头部的值
1 2 3 4 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 = "../H5/index.html" ; }
history 对象 window 对象给我们提供了一个 history 对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL
history对象方法
作用
back()
后退功能
forward()
前进功能
go(参数)
前进后退功能,参数是1,前进一个页面。参数-1,后退一个页面
PC网页特效 元素偏移量 offset 系列 offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
获得元素距离带有定位父元素的位置
获得元素自身的大小(宽度高度)
注意: 返回的数值都不带单位
案例获取盒子鼠标的坐标
1 2 3 4 5 X = pageX - offsetLeft Y = pageY - offsetTop
拖拽模态框案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var box = document .querySelector(".box" ); box.addEventListener("mousedown" , function (e ) { var x = e.pageX - this .offsetLeft var y = e.pageY - this .offsetTop document .addEventListener("mousemove" , move) function move (e ) { box.style.left = e.pageX - x + 'px' box.style.top = e.pageY - y + 'px' console .log(x,y); } document .addEventListener('mouseup' ,function ( ) { document .removeEventListener('mousemove' ,move) }) })
仿京东图片放大镜案例
1 2 3 4 5 6 7 <div class ="box" > <img src ="./images/1.jpg" alt ="" > <div class ="mask" > </div > <div class ="bigimage" > <img src ="./images/1.jpg" alt ="" > </div > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 var box = document .querySelector('.box' ); var mask = document .querySelector('.mask' ); var bigimage = document .querySelector('.bigimage' ); var bigimg = document .querySelector('.bigimage img' ); box.addEventListener('mouseover' ,function ( ) { mask.style.display = 'block' ; bigimage.style.display = 'block' ; }) box.addEventListener('mouseout' ,function ( ) { mask.style.display = 'none' ; bigimage.style.display = 'none' ; }) box.addEventListener('mousemove' ,function (e ) { var x = e.pageX - box.offsetLeft; var y = e.pageY - box.offsetTop; var maskX = x - mask.offsetWidth / 2 ; var maskY = y - mask.offsetHeight / 2 ; moveMax_X = box.offsetWidth - mask.offsetWidth; moveMax_Y = box.offsetHeight - mask.offsetHeight; mask.style.left = maskX<=0 ?maskX=0 +'px' :maskX+'px' mask.style.left = maskX>=moveMax_X?maskX=moveMax_X+'px' :maskX+'px' mask.style.top = maskY<=0 ?maskY=0 +'px' :maskY+'px' mask.style.top = maskY>=moveMax_Y?maskY=moveMax_Y+'px' :maskY+'px' var bigMax = bigimg.offsetWidth - bigimage.offsetWidth; var bigX = maskX * bigMax / moveMax_X; var bigY = maskY * bigMax / moveMax_Y; bigimg.style.left = -bigX + 'px' ; bigimg.style.top = -bigY + 'px' ; })
元素可视区 client 系列
client 系列的相关属性来获取元素可视区的相关信息,通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等
立即执行函数
1 2 3 4 5 6 7 8 9 10 (function ( ) {})(); 或者 (function ( ) {}()); (function (a,b ) { console .log(a +b) })(a,b)
PS:如果有多个立即执行函数,需要用分号隔开
立即执行函数 this 始终指向 Window
scroll 得到的是内容的大小,client 是盒子的大小
scroll事件
1 2 3 scroll 是 是滚动条的事件,侧边栏的效果就是 通过scroll事件来确定的 element.scrollTop 是滚动条移动,上面移除的部分高度 获取页面移除的高度 window .pageYOffset
mouseover 和 mouseenter 进入盒子事件的区别
mouseover 进入盒子触发,进入子盒子仍然触发
mouseenter 进入该盒子触发,子盒子不触发
原因:mouseenter 不会有冒泡阶段
和 mouseenter 对应的是 mouseleave 同样没有冒泡阶段
动画函数封装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function animate (obj,target ) { clearInterval (obj.timer); obj.timer = setInterval (function ( ) { if (obj.offsetLeft >= target){ clearInterval (obj.timer); } obj.style.left = obj.offsetLeft +1 + 'px' ; },30 ); } var div = document .querySelector('div' );animate(div,200 );
1.缓动动画效果
公式:(目标值 - 现在的位置)/ 10
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function animate (obj,target ) { clearInterval (obj.timer); obj.timer = setInterval (function ( ) { var step = (target - obj.offsetLeft) / 10 step = step > 0 ?Math .ceil(step):Math .floor(step) if (obj.offsetLeft >= target){ clearInterval (obj.timer); } obj.style.left = obj.offsetLeft + step + 'px' ; },15 ); } var div = document .querySelector('div' );animate(div,400 );
2.动画函数添加回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function animate (obj,target,callback ) { if (obj.offsetLeft >= target){ clearInterval (obj.timer); if (callback){ callback(); } } animate(div,200 ,function ( ) { })
3.完整的动画封装 animate.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function animate (obj,target,callback ) { clearInterval (obj.timer) obj.timer = setInterval (function ( ) { var step = (target - obj.offsetLeft) / 10 step = step > 0 ?Math .ceil(step):Math .floor(step) if (obj.offsetLeft>=target){ clearInterval (obj.timer) callback && callback(); } obj.style.left = obj.offsetLeft + step + 'px' ; },15 ) }
4.轮播图
无缝滚轮连接,将第一张图片复制到最后一张,当到最后一张无动画跳到第一张,接着轮播
节流阀:
防止轮播图按钮连续点击造成播放过快。
节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
核心实现思路:设置一个变量,锁住函数和解锁函数,利用动画的回调函数解锁
5.封装返回顶部动画
1 2 3 4 5 6 7 8 9 10 11 12 13 animate(window ,0 ); function animate (obj,target,callback ) { clearInterval (obj.timer); obj.timer = setInterval (function ( ) { var step = (target - window .pageYOffset) / 10 ; step = step > 0 ? Math .ceil(step) : Math .floor(step); if (window .pageYOffset == target){ clearInterval (obj.timer); callback && callback(); } window .scroll(0 ,window .pageYOffset + step); },15 ) }
移动端网页特效 1. DOM触屏事件
touchstart
触摸事件
touchmove
触摸移动事件
touchend
触摸离开事件
当手机按压某块内容,先触发 touchstart
,如果不松手并移动就触发 touchmove
,松手就触发 touchend
2.触摸事件对象
TouchEvent 是一类描述手指在触摸屏幕的状态变化的事件。这类事件描述一个或多个触点。
常用触摸元素 targetTouches
1 2 3 1. touches 正在触摸屏幕手指的一个列表 2. targetTouches 正在触摸当前 DOM 元素上的手指的一个列表 3. changedTouches 手指状态发送了改变的列表,从无到有,从有到无的变化
3.移动端移动盒子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 var div = document .querySelector('div' );var startX = 0 ; var startY = 0 ; var x = 0 ; var y = 0 ;div.addEventListener('touchstart' ,function (e ) { startX = e.targetTouches[0 ].pageX; startY = e.targetTouches[0 ].pageY; x = this .offsetLeft; y = this .offsetTop; }) div.addEventListener('touchmove' ,function (e ) { var moveX = e.targetTouches[0 ].pageX - startX; var moveY = e.targetTouches[0 ].pageY - startY; this .style.left = x + moveX + 'px' ; this .style.top = y + moveY + 'px' ; e.preventDefault(); })
4.添加类名 classList
1 2 3 element.classList.add('newClass' );
移动类名
element.classList.remove('one')
切换类,有就删除,没有就添加
element.classList.toggle('bg')
本地存储WebStorage 本地存储特性
数据存储在用户浏览器中
设置、读取方便、甚至页面刷新不丢失数据
容量较大,sessionStorage 约5M
、localStorage 约20M
只能存储字符串,可以将对象 JSON.stringify()
编码后存储
通过JSON.parse()
解析
1.window.sessionStorage
生命周期为关闭浏览器
在用一个窗口下数据可以共享
以键值对的形式存储使用
1 2 3 4 5 6 7 8 sessionStorage.setItem(key,value) sessionStorage.getItem(key) sessionStorage.removeItem(key) sessionStorage.clear()
2.window.localStorage
生命周期永久生效,除非手动删除 否则关闭页面也会存在
可以多窗口共享(同浏览器可以共享)
以键值对的形式存储
1 2 3 4 5 6 7 8 localStorage .setItem(key,value)localStorage .getItem(key)localStorage .removeItem(key)localStorage .clear()