给ul下面多个li绑定监听事件

1,041 阅读1分钟

给ul下面多个li绑定监听事件

这是一个非常常见的面试题

方法1

给ul下面每一个li标签都绑定点击事件。

var itemli = document.getElementsByTagName("li");

for(var i = 0; i<itemli.length; i++){

    itemli[i].index = i; //给每个li定义一个属性索引值

    itemli[i].onclick = function(){

      alert(this.index+this.innerHTML); 

    }

}

方法2(JS事件代理)

从方法1中可以看出,当逐个给每个li绑定监听事件,当li太多之后,需要绑定很多监听器,(未清除监听事件)可能会导致内存泄漏,也让代码变得复杂;并且频繁的操作DOM是非常消耗性能的,如果有1000个li,怎么办呢?我们还有另一种思路,事件代理,又称事件委托

简单的来讲就是利用JS中事件的冒泡属性,把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务

所以我们可以只给ul标签绑定监听事件,点击li会通过冒泡触发ul的click事件,然后也可以实现。

var ul = document.querySelector("ul");
  ulItem.onclick = function (e) {
  e = e || window.event; //这一行及下一行是为兼容IE8及以下版本
  var target = e.target || e.srcElement;
  if (target.tagName.toLowerCase() === "li") {
    var li = this.querySelectorAll("li");
    index = Array.prototype.indexOf.call(li, target);
    alert(target.innerHTML + index);
  }
}

实际使用场景示例:

import React from 'react'; import { useEffect } from 'react';
import './css/index.css';
function App() {
    const list = [
        { id: "10002", name: 'book1' },
        { id: "10003", name: 'book2' },
        { id: "10004", name: 'book3' }

    ]
    function liClickHandle(event) {
        event = event || window.event;
        var target = event.target || event.srcElement;
        console.log(target.id);
        switch (target.id) {
            case "10002":
                console.log(target)
                break;
            case "10003":
                console.log(target)
                break;
            case "10004":
                console.log(target)
                break;
            default:
                console.log("error")
        }
    }
    useEffect(() => {
        var ul = document.getElementById("ulid");
        ul.addEventListener('click', liClickHandle, false);
        return () => {
            ul.removeEventListener('click', liClickHandle, false);
        };
    }, [])
    return (
        <div className="App">
            <ul id="ulid">
                {
                    list.map((item, index) => {
                        return (<li id={item.id} key={item.id}>{item.name}</li>)
                    })
                }
            </ul>
        </div>
    );
}
export default App;

监听事件:

addEventListener(event, function, useCapture);

第一个参数是事件的类型(比如 "click" 或 "mousedown")。 第二个参数是当事件发生时我们需要调用的函数。 第三个参数是布尔值,指定使用事件冒泡还是事件捕获。此参数是可选的。 useCapture默认值是 false,将使用冒泡传播,如果该值设置为 true,则事件使用捕获传播。

在 HTML DOM 中有两种事件传播的方法:冒泡和捕获。

事件传播是一种定义当发生事件时元素次序的方法。假如

元素内有一个

,然后用户点击了这个

元素,应该首先处理哪个元素“click”事件?

在冒泡中,最内侧元素的事件会首先被处理,然后是更外侧的:首先处理

元素的点击事件,然后是

元素的点击事件。 在捕获中,最外侧元素的事件会首先被处理,然后是更内侧的:首先处理
元素的点击事件,然后是

元素的点击事件。