事件高级使用

158 阅读3分钟

事件对象:

定义:

一个包含事件触发时的所有相关信息的对象

获取事件对象:

事件绑定的回调函数(即执行函数)的第一个参数固定是事件对象

一般命名方式: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>

\