事件对象:
定义:
一个包含事件触发时的所有相关信息的对象
获取事件对象:
事件绑定的回调函数(即执行函数)的第一个参数固定是事件对象
一般命名方式:event、ev、e
鼠标事件对象绑定对象为document、body(但需要设置宽高)
//mousemove,鼠标移动
事件对象常用属性
一、type
event.type = '当前事件类型'
二、clientX、clientY(ke lai t)
PS:名词解释
1、浏览器可见窗口:浏览器网页界面,不包括地址栏等等
2、屏幕窗口screen:设备实际屏幕的左上角
//获取光标相对与浏览器可见窗口左上角的位置
event.clientX = x轴距离,单位为
event.clientY = y轴距离,单位为
三、offsetX/offsetY
PS:名词解析
1、当前DOM元素:当前页面元素的盒子
//获取光标相对与当前DOM元素左上角的位置
event.offsetX = x轴距离,单位为:
event.offsetY = y轴距离,单位为:
四、key
PS:
1、key/keyCode/which的区别
//用户按下的键盘值
event.key = keyValue
//不提倡使用keyCode
event.keyCode = 编码值
//which
event.which = 一般等于keyCode
事件流:
定义:
事件完整执行过程中的流动路径
事件的顺序:例如:
1、点击事件,一开始接收到点击的是document--->body--->div-->button
2、看到的页面----完成的画面
实际的组成----一组图层重叠构成
点击一个局域----实际点击了多个图层的同一位置
阶段:
一、捕获阶段:从父到子
定义:从DOM的根元素开始去执行对应的事件
事件捕获需要对应代码才能看到结果
L0(on)事件监听则只有冒泡阶段
捕获一定需要,否则无法寻找到事件源
DOM.addEventListener(‘事件类型’,事件处理函数,是否使用捕获机制)
//当第三个参数为true时,事件从外到内触发
//
目标阶段:到达目标具体节点
二、冒泡阶段:从子到父
定义:当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发
事件冒泡是默认存在的
影响: 子元素的事件会影响父代事件的触发,不利于事件的独立性,所以需要限制事件执行范围,阻止事件流动
同样触发的是:同类型的事件,执行函数无需相同
阻止事件流动:
阻止事件流动需要事件对象
语法:
//阻止传播,针对冒泡阶段
event.stopPropagation()
方法可以阻断事件流动传播,在冒泡与捕获阶段都生效
事件类型的新旧区别
//mouseover和mouseout,鼠标经过与移出
//两个都有冒泡效果
//mouseenter 和 mouseleave 鼠标进入与离开
//两个没有冒泡效果,(推荐)
阻止默认行为:
语法:
event.preventDefault()
例如:表单提交,链接跳转
事件委托:
PS:事件是固定存在的,只要交互动作发生就生成,事件监听器是由我们手动设置,完成特定动作而存在的。两者概念存在根本性区别
定义:将事件监听交给父对象的行为叫做事件委托
案例:未来事件
PS:利用冒泡来为父元素设置事件覆盖所有子元素
使用场景:父元素是一个包含子元素的空事件外壳,子元素是动态生成的
思考:
1、这样设置的事件,要如何回溯定位到事件源呢?
//利用事件对象内属性:target目标
event.target = node对象(事件源)
//提前为子元素创建标识,通过classList.contains或者id进行判断特定元素
//event.target.localName = '标签名'
2、若父元素存在相同事件,如何处理呢?
综合案例:
购物车页面:
题目要求:列表渲染、列表功能操作、底部栏同步信息
核心代码:
<body>
<div class="car">
<table>
<thead>
<tr>
<th><input type="checkbox" id="all" />全选</th>
<th>商品</th>
<th>单价</th>
<th>商品数量</th>
<th>小计</th>
<th>操作</th>
</tr>
</thead>
<tbody id="carBody">
<tr>
<td>
<input class="s_ck" type="checkbox" />
</td>
<td>
<img src="./images/01.jpg" />
<p>黑马键盘</p>
</td>
<td class="price">1000¥</td>
<td>
<div class="count-c clearfix">
<button class="reduce">-</button>
<input type="text" value="1" />
<button class="add">+</button>
</div>
</td>
<td class="total">1000¥</td>
<td>
<a href="javascript:" class="del">删除</a>
</td>
</tr>
</tbody>
</table>
<div class="controls clearfix">
<a href="javascript:" class="del-all">删除所选商品</a>
<a href="javascript:" class="clear">清理购物车</a>
<a href="javascript:" class="pay">去结算</a>
<p>
已经选中<span id="totalCount">0</span>件商品;
总价:<span id="totalPrice" class="total-price">0¥</span>
</p>
</div>
</div>
<script>
//渲染函数
let init = function () {
//获取表格tbody元素
let tableList = document.querySelector('#carBody')
let htmlStr = ``
let totalCount=0,totalPrice=0
//遍历数组
dataArr.forEach((v, i) => {
htmlStr += `
<tr id='${v.id}'>
<td>
<input class="s_ck" type="checkbox" ${v.state ? 'checked' : null}/>
</td>
<td>
<img src="${v.img}" />
<p>${v.name}</p>
</td>
<td class="price">${v.price}¥</td>
<td>
<div class="count-c clearfix">
<button class="reduce" disabled=${v.count<=0?true:false}>-</button>
<input type="text" value="${v.count}" />
<button class="add">+</button>
</div>
</td>
<td class="total">${v.price * v.count}¥</td>
<td>
<a href="javascript:" class="del">删除</a>
</td>
</tr>
`
totalCount += v.state?1:0
totalPrice += v.state?v.price*v.count:0
})
//渲染列表
tableList.innerHTML = htmlStr
//渲染统计框
let totalCountDom = document.querySelector('#totalCount')
totalCountDom.innerHTML = `${totalCount}`
let totalPriceDom = document.querySelector('#totalPrice')
totalPriceDom.innerHTML = `${totalPrice}¥`
}
init()
//全选反选
let addCheck = document.querySelector('#all')
addCheck.addEventListener('click', function () {
//检测checked属性
let checkedValue = this.checked
// console.log(checkedValue);
//遍历数组,使state等于全选值
dataArr.forEach((v, i) => {
v.state = checkedValue
})
// 重新渲染
init()
})
//列表元素事件委托
let commodityTable = document.querySelector('#carBody')
commodityTable.addEventListener('click', function (e) {
console.log(typeof e.target.localName, e.target.localName);
//商品选择框函数
let commodCheck = function (obj) {
//获取id值
// console.log(obj.parentNode.parentNode.id);
let id = obj.parentNode.parentNode.id
//定义全选判断关键字
let isAllKey = true
//遍历数据查找
dataArr.forEach((v, i) => {
//使目标对应数据state = obj.checked
v.state = v.id == id ? obj.checked : v.state
//处理关键字
isAllKey = isAllKey && v.state
})
//对全选按钮赋值
document.querySelector('#all').checked = isAllKey
}
//商品数量加减函数
let commodCount = function (obj) {
//获取target的类,多个类利用contains
let btnClass = obj.className
//获取数量value,根据id获取
let id = obj.parentNode.parentNode.parentNode.id
if (btnClass === 'reduce') {
// 遍历数组查找数量
dataArr.forEach((v, i) => {
v.count = v.id == id ? v.count - 1 : v.count
})
} else {
// 遍历数组查找数量
dataArr.forEach((v, i) => {
v.count = v.id == id ? v.count + 1 : v.count
})
}
}
//列表删除函数
let commodDel = function (obj) {
//获取id
let id = obj.parentNode.parentNode.id
//遍历过滤数据
dataArr = dataArr.filter((v,i)=>{
return v.id != id
})
}
switch (e.target.localName) {
case 'input':
//商品选择框功能
commodCheck(e.target)
init()
break;
case 'button':
//商品数量加减功能
commodCount(e.target)
init()
break;
case 'a':
//列表删除功能
commodDel(e.target)
init()
break;
}
})
//多选删除事件
let delSelect = document.querySelector('.del-all')
delSelect.addEventListener('click',function(){
//遍历数据,删除选中数据
dataArr = dataArr.filter((v,i)=>{
return !v.state
})
init()
})
//清空车
let delAll = document.querySelector('.clear')
delAll.addEventListener('click',function(){
dataArr.length = null
init()
})
</script>
</body>
</html>
\