- 案例的详细解读和实现方式,自己的经验总结
js 中的事件绑定
事件是在编程时系统内发生的动作或者发生的事情,因此为元素做事件绑定是一项必不可少的事情。在 JavaScript 中,事件绑定有三种方法。
在 DOM 元素中直接绑定
和 CSS 一样,可以直接用 行内式 的方式为元素绑定事件。具体语法代码为 on+事件名="方法"
<button onclick="alert('警告框')">点击我,弹出警告框</button>
这样就为按钮绑定了一个点击事件。
这个方法的优点:
- 非常简单和稳定,可以确保它在你使用的不同浏览器中运作一致
- 处理事件时,
this关键字引用的是当前元素
这个方法的缺点:
- 不利于行为和结构相分离,耦合度太高,不建议在项目中使用。
- 在遇到相同类型的事件时,只会去处理第一个事件,而忽略后续的事件。
- 传统方法只会在事件冒泡中运行,而非捕获和冒泡
- 事件对象参数(
e)仅非IE浏览器可用
在 JavaScript 代码中绑定
为了解决方面所述的问题,早期的 JavaScript 提供了在 JavaScript 中(即script 双标签中)绑定事件。具体语法为 on+事件名=function(){} 。
<button>点我</button>
let btn = document.querySelector('button')
btn.onclick = function() {
console.log('我被点击啦');
}
这个方法的优点:
- 将行为与结构分离开了
- 非常简单和稳定,可以确保它在你使用的不同浏览器中运作一致
- 处理事件时,this关键字引用的是当前元素
这个方法的缺点同样很明显:
-
仅仅解决了结构分离的问题,但依旧只能在事件冒泡中运行,无法在事件捕获中进行。
-
一个元素一次只能绑定一个事件处理函数。新绑定的事件处理函数会覆盖旧的事件处理函数
btn.onclick = function() { console.log('123'); } btn.onclick = function() { console.log('456'); }最后只会弹出 456 ,因为 123 的方法已被覆盖。
该事件的解绑方式:
对象.on事件名字=null;
绑定事件监听函数
为了再解决以上问题,推出了靠事件监听绑定的机制。其原理是,通过事件监听,让程序检测是否有事件产生,一旦有事件触发,就立即调用一个函数做出响应,也称为 注册事件.当用户触发了特定的条件,就会触发回调函数。
btn.addEventListener('click', function(e) {
let newli = document.createElement('li')
newli.innerHTML = `我是新来的`
ul.appendChild(newli)
})
注意:
该事件类型没有
on前缀。
这个方法的优点:
- 该方法同时支持事件处理的捕获和冒泡阶段。事件阶段取决于
addEventListener最后的参数设置:false(冒泡) 或true(捕获)。 - 在事件处理函数内部,
this关键字引用当前元素。 - 事件对象总是可以通过处理函数的第一个参数(
e)捕获。即可以做事件委托的操作。 - 可以为同一个元素绑定你所希望的多个事件,同时并不会覆盖先前绑定的事件
这个方法的缺点:
IE 不支持,你必须使用 IE 的 attachEvent 函数替代。
该事件的解绑方式:
解绑事件 对象.removeEventListener(“事件类型”,函数名字,false);
全选操作的基本实现
事件绑定中,全选是一项基本的操作,常用于购物车等案例。
点击全选框让复选框跟着变化
点击全选框让复选框被选中或取消,其实只需要先用一个变量获取全选框的 被选中状态 ,然后遍历所有复选框,让他们的选中状态等于全选框的选中状态即可。代码如下所示。
checkAll.addEventListener('click', function() {
let status = this.checked
cks.forEach(ele => {
ele.checked = status
})
all.innerHTML = status ? '取消' : '全选'
})
也可以不用变量来接收全选框的被选中状态,直接 用三元表达式 判断即可,因为全选框的被选中状态返回值是一个布尔值。因此代码可以改为以下形式。
checkAll.addEventListener('click', function() {
cks.forEach(ele => {
ele.checked = status
})
all.innerHTML = checkAll.checked ? '取消' : '全选'
})
点击全部复选框让全选框被选中
方法一
可以先声明一个变量,初始值设为 true ,默认所有的复选框被选中,然后循环遍历所有的复选框的被选中状态,只要有一个复选框没被选中,直接把变量改为 false 。最后让全选框被选中状态等于这个变量。代码如下所示。
cks.forEach(element => {
element.addEventListener('click', function() {
let flag = true
cks.forEach(ele => {
if (ele.checked === false) {
flag = false
}
})
all.innerHTML = flag ? '取消' : '全选'
checkAll.checked = flag ? true : false
})
})
方法二
已知有3个复选框,如果有3个复选框被选中,全选框也会进入选中状态。简单来说,如果 复选框被选中的数量等于复选框的总数 ,则说明全部复选框都被选中了。因此可以设置一个变量赋初始值为0,循环遍历所有复选框,只要有一个复选框被选中,则让该变量自增一,最后与复选框的总数做判断。语法代码如下。
cks.forEach(element => {
element.addEventListener('click', function() {
// 每点击一次复选框,判断全部的复选框的选中状态。
let count = 0;
// 设置一个变量,每次触发点击事件让其值为0。
cks.forEach(ele => {
// 如果有一个复选框被选中,则让变量count自增1
if (ele.checked === true) {
count++
}
})
if (count === cks.length) {
checkAll.checked = true
all.innerText = '取消'
} else {
checkAll.checked = false
all.innerText = '全选'
}
})
})
js 中的排他思想
JavaScript 中排他思想一般用在 Tab 切换中。排他思想的方法为,干掉所有人,留下我自己。
因此,可以先遍历 Tab 栏中所有元素,去掉所有元素的类名。去掉类名的方法为 事件元素.className='' ,或者 事件元素.classList.remove(类名) 。在不知道该事件源的类名数量情况下建议使用后者。
然后再给触发事件的那个元素添加类名。谁触发函数就给谁加,就用到了 this 指向(谁触发函数 this 就指向谁)以及事件对象 e.target 。
代码如下所示
lis.forEach(element => {
element.addEventListener('click', function() {
lis.forEach(ele => {
ele.classList.remove('active')
this.classList.add('active')
})
})
})
又或者可以换种思路,专门找到有类名的那个事件源,去除他的类名,再给触发事件的元素节点添加类名,这样就不需要循环遍历去除所有元素的类名了。代码如下所示。
lis.forEach(element => {
element.addEventListener('click', function() {
document.querySelector('li.active').classList.remove('active')
this.classList.add('active')
})