事件流的传播阶段(顺序)
- 捕获阶段
- 目标阶段
- 冒泡阶段
事件流的两种模式
- 冒泡模式:从里到外逐层执行,常用的一种模式,也是默认模式
- 捕获模式:从外到内逐层执行,火狐提出来的,ie6,7,8不支持,很少使用
阻止事件冒泡的方法
- stopPropagation 阻止冒泡,有兼容问题
e.stopPropagation() //阻止事件冒泡 常用的方法 兼容问题
- cancelBubble 取消冒泡,兼容低版本
// 兼容写法 兼容ie8及以下
e.cancelBubble = true
- 兼容写法
//兼容写法
e . stopPropagation ? e . stopPropagation():e . cancelBubble = true
阻止默认行为
- preventDefault(event对象的方法),有兼容问题
e . preventDefault()
- returnValue(event对象的方法)。ie的兼容写法
e . returnValue =false
- 兼容写法
e . preventDefault?e . preventDefault():e . returnValue =false
- return false
//对应的右键点击
window.oncontextmenu = function(e){
console.log('右键点击了')
return false //一定要放在最后
}
示例:右键自定义菜单栏,具有前进、后退、刷新、换肤功能
css代码
<style>
* {
margin: 0;
padding: 0;
}
ul {
display: none;
width: 80px;
height: 120px;
border: 1px solid #000;
position: absolute;
}
li {
list-style: none;
height: 24px;
background-color: #ccc;
}
</style>
html代码
<ul>
<li onclick="history.forward()">前进</li>
<li onclick="history.back()">后退</li>
<li onclick="location.reload()">刷新</li>
<li onclick="document.body.style.backgroundColor=randomColor()">换肤</li>
<li onclick="print()">打印</li>
</ul>
js代码
<script>
// 右键自定义菜单栏,具有前进、后退、刷新、换肤功能
var ul = document.querySelector('ul')
document.oncontextmenu = function(e) {
e = e || window.event
// 取消右击默认属性
e.preventDefault ? e.preventDefault() : e.returnValue
// 右击ul隐藏
ul.style.display = 'block'
// 鼠标右击时,ul随页面点击位置改变
ul.style.left = e.pageX + 'px'
ul.style.top = e.pageY + 'px'
}
ul.onmouseover = function(e) {
e = e || window.event
if (e.target.tagName == 'LI') {
for (var item of this.children) {
item.style.backgroundColor = '#ccc'
item.style.color = '#000'
}
e.target.style.backgroundColor = '#666'
e.target.style.color = '#fff'
}
}
// 当点击完毕后ul要隐藏
ul.onclick = function(e) {
e = e || window.event
if (e.target.tagName == 'LI') {
this.style.display = 'none'
}
}
// 随机颜色
function randomColor() {
var r = Math.random() * 256
var g = Math.random() * 256
var b = Math.random() * 256
return `rgb(${r},${g},${b})`
}
</script>
事件监听器
eventListener 他是一个标准的观察者模式,他是通过对应的监听器来监听事件的触发和执行。
两个方法
- addEventListener(事件名,函数名(函数),模式): 添加事件监听器
- 事件冒泡和事件捕获的监听同时进行,那么会优先监听到事件捕获
- 该方法可以监听多个处理函数,而onclick这种属性赋值的方法只可以进行一次,后写的会覆盖先写的
- 事件名可以自定义
- removeEventListener(要移除的事件名,要移除的函数名,模式): 移除事件监听器
- 移除监听事件,里面的三个参数必须全部一致
- 如果添加事件监听器的时候传入处理函数为匿名处理函数 那么不能被移除(对象比对的是地址)
<div onclick="console.log('我被电击了');">
<button onclick="console.log('别点我');">按钮
<p onclick="console.log('点div去');"></p>
</button>
</div>
<script>
var div = document.querySelector('div')
var btn = document.querySelector('button')
btn.addEventListener('click', function() {
console.log('1');
}, false) //冒泡事件
btn.addEventListener('click', function() {
console.log('3');
}, true) //捕获事件,会先执行
btn.addEventListener('click', function() {
console.log('2');
}) //冒泡事件
// 移除监听事件,里面的三个参数必须全部一致
btn.addEventListener('click', headle, false) //冒泡事件
btn.removeEventListener('click', headle, true)
function headle() {
console.log('5');
} //冒泡事件
// 内置属性的移除事件,
document.querySelector('div').onclick = null
</script>
拖拽
拖拽原理
- 给对应的需要拖拽的元素添加鼠标按下事件
- 在按下事件内添加给区间的元素对应的鼠标移动事件
- 在按下事件内给document添加对应的鼠标弹起事件 在弹起事件中释放移动事件及释放弹起事件
基础拖拽
【思路】
- 获取拖拽的元素
- 给拖拽元素添加鼠标按下事件 并记录按下的坐标(在对应的盒子里的坐标)
- 在按下事件内给区间元素添加鼠标移动事件 并记录每次移动的坐标
- 在区间元素的鼠标移动事件中 设置对应的拖拽元素的坐标(移动的坐标 = 当前的坐标 - 鼠标点击位置的坐标 + 'px')
- 在按下事件内在document中添加鼠标弹起事件 并释放之前的移动事件及自身的弹起事件
<style>
div {
width: 100px;
height: 100px;
background-color: aquamarine;
position: absolute;
}
</style>
</head>
<div></div>
<script>
var div = document.querySelector('div')
div.onmousedown = function(e) {
e = e || window.event
// 先获取在div内的点击坐标
var x = e.offsetX
var y = e.offsetY
// 带获取点击在页面的坐标
document.onmousemove = function(e) {
e = e || window.event
var currentX = e.pageX
var currentY = e.pageY
div.style.left = currentX - x + 'px'
div.style.top = currentY - y + 'px'
}
div.onmouseup = function(e) {
document.onmousemove = null
}
}
</script>
区间拖拽
offset家族(属于元素对象)
- offsetParent 偏移的父元素 (从里到外找有定位的父元素 没有的话就是body)
- offsetLeft 左偏移量 (不包含偏移的父元素本身的margin 包含偏移的父元素本身padding、border)
- offsetTop 上偏移量
- offsetHeight 偏移元素的高度 (包含padding及border 不包含margin)
- offsetWidth 偏移元素的宽度
【思路 】
- 获取拖拽的元素
- 给拖拽元素添加鼠标按下事件 并记录按下的坐标(在对应的盒子里的坐标)
- 在按下事件内给区间元素添加鼠标移动事件 并记录每次移动的坐标
- 在区间元素的鼠标移动事件中 获取对应的区间元素的位置 及 能够移动的距离 (区间元素的宽/高度 - 自身的宽/高度)
- 设置移动元素处在区间元素的位置
- 移动位置在父元素的坐标 = 页面的位置 - 父元素离页面的位置- 鼠标点击的位置
- 对应坐标位置进行区间判断 小于0的时候值应该设置为0 大于能够移动的距离设为最大的距离
- 在按下事件内在document中添加鼠标弹起事件 并释放之前的移动事件及自身的弹起事件
<style>
.box1 {
width: 300px;
height: 300px;
/* position: relative; */
background-color: palevioletred;
}
.box2 {
width: 50px;
height: 50px;
position: absolute;
background-color: peachpuff;
}
</style>
<div class="box1">
<div class="box2">
</div>
</div>
<script>
var box1 = document.querySelector('.box1')
var box2 = document.querySelector('.box2')
box2.onmousedown = function(e) {
e = e || window.event
var x = e.offsetX
var y = e.offsetY
box1.onmousemove = function(e) {
e = e || window.event
var box1X = this.offsetLeft
var box1Y = this.offsetTop
var maxW = this.offsetWidth - box2.offsetWidth
var maxH = this.offsetHeight - box2.offsetHeight
var targetX = e.pageX - x - box1X
var targetY = e.pageY - y - box1Y
if (targetX > maxW) {
targetX = maxW
}
if (targetX < 0) {
targetX = 0
}
if (targetY > maxH) {
targetY = maxH
}
if (targetY < 0) {
targetY = 0
}
box2.style.left = e.pageX - x - box1X + 'px'
box2.style.top = e.pageY - y - box1Y + 'px'
}
document.onmouseup = function() {
box1.onmousemove = document.onmouseup = null
}
}
</script>
封装一个方法找盒子到页面的距离
function getBoxToPageDistance(element){
var distance = {
x:0,
y:0
} //距离对象
while(element.offsetParent){ //找到body就停止
distance.x += element.offsetLeft
distance.y += element.offsetTop
element = element.offsetParent
}
return distance
}