WebAPIs第四天

本文介绍了WebAPIs中关于事件处理的概念,包括如何获取和使用事件对象,如clientX/clientY、offsetX/offsetY属性,以及跟随鼠标移动的案例。同时,文章讲解了事件流的两个阶段——捕获和冒泡,如何阻止事件传播和默认行为,以及使用addEventListener与onclick的区别。此外,还讨论了事件委托的原理和优势,并提供了一个购物车案例来演示其应用。
摘要由CSDN通过智能技术生成

Web APIs第四天

DOM- 事件高级

1. 事件对象

1. 获取事件对象

  1. 事件对象是个对象, 这个对象里有事件触发时的相关信息
  2. 例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息
  3. 获取: 在事件绑定的回调函数的第一个参数就是事件对象, 一般命名为event、ev、e
// 1. 事件对象
let num1 = document.querySelector('button')
num1.addEventListener('click', function (e) {
    console.log(e)
})

2. 事件对象常用属性

  1. 部分常用属性: type 获取当前的事件类型
  2. clientX/clientY: 获取光标相对于浏览器可见窗口左上角的位置
  3. offsetX/offsetY: 获取光标相对于当前DOM元素左上角的位置
  4. key: 用户按下的键盘键的值, 现在不提倡使用keyCode
// 2. 事件对象常用属性
document.addEventListener('click', function (e) {
    // 当前视口坐标
    console.log(e.clientX, e.clientY)
    // 整个页面坐标
    console.log(e.pageX, e.pageY)
    // 当前元素坐标
    console.log(e.offsetX, e.offsetY)
})
跟随鼠标案例:
需求:一张图片一直跟着鼠标移动
// 3. 跟随鼠标案例
let img = document.querySelector('img')
document.addEventListener('mousemove', function (e) {
    // 不断获取当前鼠标坐标 把坐标给图片
    img.style.top = e.pageY  + -30 + 'px'
    img.style.left = e.pageX + -30 +'px'
})
按下回车发布微博案例:
①:用到按下键盘事件 keydown 或者 keyup 都可以
②:如果用户按下的是回车键盘,则发布信息
③:按下键盘发布新闻,其实和点击发布按钮效果一致 send.click()
// 1.事件侦听三要素 键盘事件 发布信息
// 2.keyup 按下键盘松开后触发
// 3.keydown 按下键盘就触发  场景: 拖拽使用
text.addEventListener('keyup', function (e) {
    // console.log(e)   // e.keyCode(废弃)
    // 4.现使用key
    console.log(e.key)
    if (e.key == 'Enter') {
        // 5.自动触发点击按钮
        send.click()
    }
})

2. 事件流

1. 事件流和两个阶段说明

  1. 事件流指的是事件完整执行过程中的流动路径
  2. 说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段
  3. 简单来说:捕获阶段是 从父到子 冒泡阶段是从子到父

2. 事件捕获和事件冒泡

事件冒泡概念:
  1. 当一个元素事件被触发时, 同样的事件将会在该元素的所有祖先元素中依次被触发, 这一过程被称为事件冒泡
  2. 简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
  3. 事件冒泡是默认存在的
事件捕获概念:
  1. 从DOM的根元素开始去执行对应的事件 (从外到里)
  2. 事件捕获需要写对应代码才能看到效果
说明:
  1. addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
  2. 若传入false代表冒泡阶段触发,默认就是false
  3. 若是用 L0 事件监听,则只有冒泡阶段,没有捕获
// 1. 冒泡事件阶段(理解)
let num1 = document.querySelector('.box')
let num2 = document.querySelector('.box1')
num1.addEventListener('click', function (e) {
    alert('我是爸爸')
    e.stopPropagation()
// 2. 捕获事件阶段(了解)
}, true)
num2.addEventListener('click', function (e) {
    alert('我是儿子')
})

3. 阻止事件流动

  1. 因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
  2. 若想把事件就限制在当前元素内,就需要阻止事件流动
  3. 阻止事件流动需要拿到事件对象
  4. 此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效
// 3. 阻止事件流动 Propagation(传播)
    e.stopPropagation()
}, false)
鼠标经过事件:
  1. mouseover 和 mouseout 会有冒泡效果
  2. mouseenter 和 mouseleave 没有冒泡效果(推荐)
// mouseover/out会有冒泡 enter/leave没有(推荐)
num1.addEventListener('mouseover', function () {
    console.log(11)
})
阻止默认行为,比如链接点击不跳转,表单域的跳转
// 5. 阻止默认行为 方法 链接不跳转/表单并提交
let num3 = document.querySelector('a')
num3.addEventListener('click', function (e) {
    e.preventDefault()
    e.stopPropagation()
})
两种注册事件的区别:

传统on注册(L0)

  1. 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
  2. 直接使用null覆盖偶就可以实现事件的解绑, 都是冒泡阶段执行的
let num4 = document.querySelector('button')
// 多次相同事件只执行最后一次
num4.onclick = function () {
    alert('你好')
}
num4.onclick = function () {
    alert('你好1')
}
// 解除绑定事件
num4.onclick = null

事件监听注册(L2)

  1. 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)
  2. 后面注册的事件不会覆盖前面注册的事件(同一个事件)
  3. 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
  4. 必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)
  5. 匿名函数无法被解绑
let num5 = document.querySelector('.btn')
num5.addEventListener('click', function () {
    alert('你好')
})

// 2. 事件监听注册L2
// 不会覆盖前面事件
num5.addEventListener('click', add)
function add() {
    alert('你好1')
}
// 解除绑定事件
num5.removeEventListener('click', add)

3. 事件委托

  1. 事件委托是利用事件流的特征解决一些开发需求的知识技巧
  2. 优点:给父级元素加事件(可以提高性能)
  3. 原理:事件委托其实是利用事件冒泡的特点
  4. 实现:事件对象.target 可以获得真正触发事件的元素
// 不是给每个li注册事件 而是委托给父级
let num6 = document.querySelector('ul')
num6.addEventListener('click', function (e) {
    e.target.style.color = 'red'
})

4. 购物车案例

    <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" readonly />
        </td>
        <td>
          <img src="./images/01.jpg" />
          <p>牛奶</p>
        </td>
        <td class="price">5</td>
        <td>
          <div class="count-c clearfix">
            <button class="reduce" disabled>-</button>
            <input type="text" value="1" />
            <button class="add">+</button>
          </div>
        </td>
        <td class="total">5</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>
let btn = document.querySelectorAll('.reduce')
let btn1 = document.querySelectorAll('.add')
let input = document.querySelectorAll('.count-c input')
let del = document.querySelectorAll('.del')
let price = document.querySelectorAll('.price')
let total = document.querySelectorAll('.total')
let totalCount = document.querySelector('#totalCount')
let totalprice = document.querySelector('.total-price')
let carBody = document.querySelector('#carBody')
for (let num1 = 0; num1 < btn1.length; num1++) {
  total[num1].innerHTML = price[num1].innerHTML
  // 1.加号操作
  btn1[num1].addEventListener('click', function () {
    input[num1].value++
    btn[num1].disabled = false
    // console.log(parseInt(price[num1].innerHTML) * input[num1].value)
    total[num1].innerHTML = parseInt(price[num1].innerHTML) * input[num1].value + '¥'
    fn()
  })
  // 2.减号操作
  btn[num1].addEventListener('click', function () {
    input[num1].value--
      total[num1].innerHTML = parseInt(price[num1].innerHTML) * input[num1].value + '¥'
      if (input[num1].value <= 1) {
        btn[num1].disabled = true
      }
      fn()
  })
  // 4.删除操作
  del[num1].addEventListener('click', function () {
    // carBody.removeChild(carBody.children[num1])
    carBody.removeChild(this.parentNode.parentNode)
    fn()
  })
}
// 3.计算总件/总价函数
function fn() {
  let total = document.querySelectorAll('.total')
  let input = document.querySelectorAll('.count-c input')
  let num2 = 0
  let num3 = 0
  for (let num1 = 0; num1 < total.length; num1++) {
    num2 = num2 + parseInt(input[num1].value)
    num3 = num3 + parseInt(total[num1].innerHTML)
  }
  totalCount.innerHTML = num2
  totalprice.innerHTML = num3 + '¥'
}
fn()

5. 综合案例

  1. 需求:点击录入按钮,可以增加学生信息
  2. 本次案例主要目的是为了后面学习Vue做铺垫(数据驱动视图)
// 数据后端数据
let arr = [
  { stuid: 1001, uname: '欧阳霸天', age: 19, gender: '男', salary: '20000', city: '上海' },
  { stuid: 1002, uname: '令狐霸天', age: 29, gender: '男', salary: '30000', city: '北京' },
  { stuid: 1003, uname: '诸葛霸天', age: 39, gender: '男', salary: '2000', city: '北京' },
]

// 1.渲染函数
let tbody = document.querySelector('tbody')
let btn = document.querySelector('.add')
let uname = document.querySelector('.uname')
let age = document.querySelector('.age')
let gender = document.querySelector('.gender')
let salary = document.querySelector('.salary')
let city = document.querySelector('.city')
function fn() {
  // 去掉以前数据 让点击的时候tr都没有
  tbody.innerHTML = ''
  for (let num1 = 0; num1 < arr.length; num1++) {
    // 创建tr标签 然后追加给tbody
    let tr = document.createElement('tr')
    // 给a添加一个序号 才能知道删除操作删除哪一个
    tr.innerHTML = `
        <tr>
          <td>${arr[num1].stuid}</td>
          <td>${arr[num1].uname}</td>
          <td>${arr[num1].age}</td>
          <td>${arr[num1].gender}</td>
          <td>${arr[num1].salary}</td>
          <td>${arr[num1].city}</td>
          <td><a href="javascript:" id="${num1}">删除</a></td>
        </tr>
    `
    // 复原所有表单数据
    tbody.appendChild(tr)
    uname.value = age.value = salary.value = ''
    gender.value = '男'
    city.value = '北京'
  }
}
// 页面加载调用函数
fn()

// 2. 添加数据按钮
// 获得表单里的值 追加给数组 用push方法
btn.addEventListener('click', function () {
// 得到数组最后一条数据学号 1003 + 1
  arr.push({
    stuid: arr[arr.length - 1].stuid + 1, 
    uname: uname.value, 
    age: age.value, 
    gender: gender.value, 
    salary: salary.value, 
    city: city.value
  })
  // console.log(arr)
  fn()
})

// 3. 删除操作 使用事件委托来删除数组数据
tbody.addEventListener('click', function (e) {
  // 点击了A才能删除 用if判断tagNmae是否为A来删除
  // console.log(e.target.tagName);
  if (e.target.tagName == 'A') {
    // 删除数组里的数据
    // 给a添加一个序号 才能知道删除操作删除哪一个
    arr.splice(e.target.id, 1)
  }
  fn()
})

本节单词:
  1. keyup
  2. keydown
  3. enter
  4. stopPropagation
  5. mouseover
  6. preventDefault
  7. onclick
  8. removeEventListener
  9. target
  10. tagName
  11. page
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值