1、获取元素的尺寸
1、window.getComputedStyle(dom对象)
2、clientWidth/clinetHeight 内容+padding 没有px单位
3、offsetWidth/offsetHeight 内容+padding+border
2、获取定位偏移量
offsetLeft/offsetTop 每一个元素绝对有上级定位元素 如果没有最终以body计算
3、滚动距离
scrollTop/scrollLeft 滚动距离
scrollWidth/scrollHeight 滚动尺寸(完整的尺寸)
4、事件对象
1、事件对象:
事件触发时,系统会自动的调用函数 调用过程中传递了一个对象(事件对象)
2、获取事件对象
var event = e || window.event;
3、按键码
事件对象中有属性记录使用的按键(key,keyCode)
typora-root-url: img
鼠标坐标点
1、三组坐标点
<div class="div1"></div>
<div class="div2"></div>
<div class="div3"></div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function(e){
var event = e || window.event;
// offsetX,event.offsetY 以元素的左上角作为圆点计算坐标值
console.log(event.offsetX,event.offsetY);
}
divs[1].onclick = function(e){
var event = e|| window.event;
// 以浏览器的左上角为坐标圆点计算
console.log(event.clientX,event.clientY)
}
divs[2].onclick = function(event){
// 以页面文档来计算的坐标圆点
console.log(event.pageX,event.pageY)
}
</script>
2、显示坐标点案例
<!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>
</head>
<body>
<h1>X 轴坐标是 : <span class="x">950</span></h1>
<h1>Y 轴坐标是 : <span class="y">64</span></h1>
<script>
document.onmousemove = function(event){
document.querySelector('.x').innerHTML = event.pageX;
document.querySelector('.y').innerHTML = event.pageY;
}
</script>
</body>
</html>
拖拽效果
<!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>
div{ width: 100px; height: 100px; position: absolute; top:0;left:0;background-color: blue;}
</style>
</head>
<body>
<div></div>
<script>
/*
拖拽效果就是需要控制元素的top与left值
拖拽涉及到的事件:
1、鼠标按下
2、鼠标移动
3、鼠标松手 元素就固定下
*/
var divDom = document.querySelector('div');
divDom.onmousedown = function(){
// 只有鼠标按下之后移动事件才会生效。所以移动事件必须要设置在按下事件中
divDom.onmousemove = function(e){
var event = e || window.event;
var x= event.clientX - divDom.clientWidth/2;
var y = event.clientY - divDom.clientHeight/2;
divDom.style.top = y+'px';
divDom.style.left = x+'px';
}
}
// 鼠标松手之后 移动事件失效
divDom.onmouseup = function(){
// 解绑 一旦鼠标松手 将移动事件处理程序设置为null 就没有事件处理程序了 当鼠标移动时虽然可以触发 但是无效
divDom.onmousemove = null;
}
</script>
</body>
</html>
事件流
事件流机制就是关于事件的传播方向。html结构是一层嵌套一层,可以看做为一组同心圆组成。每当在标签上触
发了一个事件,都可以理解同时触发了其他标签对应的事件。所以这种叫做事件传播。早期微软与网景公司在事件
处理,看法一致(都认为在标签上触发了事件,其实也可以理解为其他的标签也触发)。最后实现事件功能时完全相
反
微软:先在事件源上触发事件,然后在向上层元素触发同名事件(冒泡模型),直到window结束
网景:先在window上触发的事件,然后在逐层向下直到事件源上触发(捕获模型)
W3C进行整合时发现两家公司观点都正确。就直接将两种模型合并到一起
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-48dGUM0J-1660913546419)(/1660879190587.png)]
事件监听
1、动态绑定的缺点
<button>按钮</button>
<script>
// 动态绑定事件,如果同一个元素 绑定多个同名事件 导致只有最后一次 生效
document.querySelector('button').onclick = function(){
console.log('张三写的代码逻辑');
}
document.querySelector('button').onclick = function(){
console.log('你的逻辑代码');
}
window.onload = function(){
console.log(1111)
}
window.onload = function(){
console.log(222)
}
/*
动态绑定为什么会出现覆盖问题
因为每次都是使用dom.事件名称= 函数进行操作,这句话多次使用 就反复的在覆盖事件的属性值
一旦事件触发 系统会自动的找到事件源dom对象调出对应的事件 然后将函数给运行
*/
</script>
2、事件监听语法
dom对象.addEventListener(事件名称,事件处理程序,模型类型)
事件名称 是没有on前缀的名称
事件处理程序,也是一个函数(如果需要使用事件对象 还是传递形参)
模型类型:要求是布尔值,false表示冒泡,true表示捕获 默认是冒泡模型
3、使用示例
<button>按钮</button>
<script>
// document.querySelector('button').addEventListener('click',function(){
// console.log('第一次绑定事件')
// })
// function fn(){
// console.log('第二次绑定')
// }
// document.querySelector('button').addEventListener('click',fn)
// addEventListener 在IE下是存在兼容性问题
document.querySelector('button').attachEvent('onclick',function(){
console.log('ie')
})
</script>
4、解决兼容性问题
/**
* 绑定事件
* @param {Document} elem 绑定事件的dom对象
* @param {String} eventName 事件名称 是没有on前缀的名称
* @param {Function} handler 事件处理程序
*/
function bindEvent(elem,eventName,handler){
if(window.addEventListener){
// 判断是w3c浏览器
return elem.addEventListener(eventName,handler);
}
return elem.attachEvent('on'+eventName,handler);
}
事件解绑
行内方式解绑
<button onclick="console.log(123)">按钮</button>
<button class="delete">解除绑定</button>
<script>
document.querySelector('.delete').addEventListener('click',function(){
document.querySelector('button').removeAttribute('onclick')
})
</script>
动态方式解绑
<button >按钮</button>
<button class="delete">解除绑定</button>
<script>
document.querySelector('button').onclick = function(){
console.log(123)
}
document.querySelector('.delete').addEventListener('click',function(){
document.querySelector('button').onclick = null;
})
</script>
事件监听解绑
1、事件解绑
<button>按钮</button>
<button class="delete">解除绑定</button>
<script>
// [function(){},function(){}]
document.querySelector('button').addEventListener('click', function () {
console.log(123);
})
function fn(){
console.log('第二个处理程序')
}
document.querySelector('button').addEventListener('click',fn);
document.querySelector('.delete').addEventListener('click', function () {
/*
解除绑定的语法
dom.removeEventListener(事件名称,事件处理程序)
当需要进行解除绑定时 事件处理程序一定要使用有名称函数
*/
document.querySelector('button').removeEventListener('click', function () {
console.log(123);
})
document.querySelector('button').removeEventListener('click',fn)
})
console.log((function(){}) == (function(){}))//false
2、解决兼容性问题
<button>按钮</button>
<button class="delete">解除绑定</button>
<script src="common.js"></script>
<script>
var btn = document.querySelector('button');
var deleteDom = document.querySelector('.delete');
function fn(){
console.log(123)
}
// 为按钮绑定点击事件
bindEvent(btn,'click',fn);
deleteDom.onclick = function(){
btn.detachEvent('onclick',fn)
}
</script>
3、封装事件解绑函数
/**
* 解除事件监听的绑定
* @param {Document} elem 绑定事件的dom对象
* @param {String} eventName 事件名称 是没有on前缀的名称
* @param {Function} handler 事件处理程序
*/
function unbindEvent(elem,eventName,handler){
try {
elem.removeEventListener(eventName,handler);
} catch (error) {
elem.detachEvent('on'+eventName,handler);
}
}
事件冒泡
<!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>
.div1{ width: 400px; height: 400px; background-color: cadetblue;}
.div2{ width: 300px; height: 300px; background-color:blue}
.div3{ width: 200px; height: 200px; background-color: pink}
</style>
</head>
<body>
<div class="div1">
<div class="div2">
<div class="div3">
</div>
</div>
</div>
<script>
document.querySelector('.div1').addEventListener('click',function(){
console.log('div1被点击')
})
document.querySelector('.div2').addEventListener('click',function(event){
console.log('div2被点击')
event.stopPropagation();
})
document.querySelector('.div3').addEventListener('click',function(event){
// 当div3被点击。触发了点击事件,继续向上传播点击事件,如果上层元素上也存在点击事件会按照顺序 执行,所以 事件冒泡存在缺点
console.log('div3被点击');
// 阻止事件冒泡
// event.stopPropagation();
// IE低版本阻止冒泡方式
event.cancelBubble=true
})
</script>
</body>
</html>
事件委托
未来元素需要处理事件 一定记得使用事件委托
1、未来元素绑定事件
<ul>
<li>浮夸</li>
<li>单车</li>
</ul>
<button>添加元素</button>
<script>
document.querySelector('button').onclick = function(){
var liDom = document.createElement('li')
liDom.innerHTML = '你好机车哦!';
document.querySelector('ul').appendChild(liDom);
}
document.querySelectorAll('li').forEach(function(dom){
dom.addEventListener('click',function(){
console.log(this.innerHTML)
})
})
</script>
2、使用事件委托解决
<!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>
</head>
<body>
<ul>
<li>浮夸</li>
<p class="mc">冒充者</p>
<li>单车</li>
</ul>
<button>添加元素</button>
<script>
document.querySelector('button').onclick = function(){
var liDom = document.createElement('li')
liDom.innerHTML = '你好机车哦!';
document.querySelector('ul').appendChild(liDom);
}
// document.querySelectorAll('li').forEach(function(dom){
// dom.addEventListener('click',function(){
// console.log(this.innerHTML)
// })
// })
// 事件委托 是借助于事件冒泡机制来实现的,子元素上触发事件后 父级元素也会触发同名事件
document.querySelector('ul').addEventListener('click',function(event){
// console.log('ul click');
// 在事件冒泡的事件处理程序中this表示的是 父级元素 不是事件源
// console.log(this);
// 在事件冒泡中事件对象下的 srcElement、target 都可以表示事件源的dom对象
// console.log(event)
// 获取标签名称
// console.log(event.target.nodeName,event.target.tagName);
// 在使用事件委托机制时 只要能够确认绑定事件的元素 即可 不一定需要使用标签名称进行判断 可以使用其他的任何条件 只要能够区分标签即可
if(event.target.nodeName == 'LI'){
console.log(event.target.innerHTML);
}else if (event.target.className == 'mc'){
console.log('aaa')
}
})
</script>
</body>
</html>
事件委托的好处:支持未来元素,避免循环绑定事件
事件委托的案例
<!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,
table tr th,
table tr td {
border: 1px solid #0094ff;
}
.layer {
width: 200px;
height: 150px;
position: absolute;
top: 200px;
left: 200px;
background-color: #ccc;
display: none;
line-height: 38px;
}
</style>
</head>
<body>
<div class="layer">
<input type="text" class="username" /> <br />
<input type="radio" class="changeSex" name="changeSex" value="男" />男
<input type="radio" class="changeSex" name="changeSex" value="女" />女<br />
<input type="text" class="age" /><br />
<button id="set">修改</button>
</div>
<div>
<input type="text" id="username" />
<input type="radio" id="sexOne" name="sex" value="男" />男
<input type="radio" id="sexTwo" checked name="sex" value="女" />女
<input type="text" id="age" />
<button id="add">添加</button>
</div>
<br />
<table cellspacing="0" border="1" width="600px">
<tr>
<td>姓名</td>
<td>性别</td>
<td>年龄</td>
<td>操作</td>
</tr>
</table>
<script>
var eidtParentDom = null;
//页面上输入用户的姓名、性别、年龄 确认后 列表的方式显示添加的数据
document.querySelector('#add').onclick = function () {
// 获取到页面上输入内容
var username = document.querySelector('#username').value;
// 获取性别 input[name="sex"]:checked 从所有input中先筛选name值为sex 并且有checked属性的input
var sex = document.querySelector('input[name="sex"]:checked').value;
var age = document.querySelector('#age').value;
// 创建tr节点
var trDom = document.createElement('tr');
trDom.innerHTML = `
<td>${username}</td>
<td>${sex}</td>
<td>${age}</td>
<td><button class="delete">删除</button></td>
`
document.querySelector('tbody').appendChild(trDom)
}
document.querySelector('table').addEventListener('click',function(event){
if(event.target.className == 'delete' ){
// 点击的是删除按钮
document.querySelector('tbody').removeChild(event.target.parentElement.parentElement)
}
})
</script>
</body>
</html>
阻止默认行为
页面中a标签与form标签具备默认行为,天生需要跳转地址
1、a标签
<!-- 1、直接在href上设置 javascript:; 表示执行空的js代码-->
<a href="javascript:;">百度</a>
<a href="" class="baidu">百度一下</a>
<script>
// 2、在动态绑定中可以return false 阻止 千万别报错
// document.querySelector('.baidu').onclick = function(){
// console.log(123)
// return false;
// }
// 3、使用事件对象
document.querySelector('.baidu').addEventListener('click',function(event){
// 阻止默认行为
event.preventDefault();
})
</script>
2、form标签
<form>
<input type="text" >
<input type="submit" class="sub" value="ok">
</form>
<script>
document.querySelector('.sub').addEventListener('click',function(event){
console.log('你的代码有bug');
event.preventDefault();
// e.returnValue = false;
})
</script>