Javascript 如何解决addEventListener的问题:无法读取属性';当前目标';未定义的

Javascript 如何解决addEventListener的问题:无法读取属性';当前目标';未定义的,javascript,dom,Javascript,Dom,我是JavaScript的新手,所以请容忍我 我正在尝试使用JavaScript为特定内容生成选项卡式窗口。HTML如下所示: <div class="tab-win" id="tablinks-d38e44"> <button class="tablinks" data-target="tab-bash-d38e44">bash</button> <button class="tablinks" data-target="tab-gui-d

我是JavaScript的新手,所以请容忍我

我正在尝试使用JavaScript为特定内容生成选项卡式窗口。HTML如下所示:

<div class="tab-win" id="tablinks-d38e44">
   <button class="tablinks" data-target="tab-bash-d38e44">bash</button>
   <button class="tablinks" data-target="tab-gui-d38e44">gui</button>
</div>

<div class="tabcontents" id="tabcontents-d38e44">
   <div class="tabcontent" id="tab-bash-d38e44">This is bash.</div>
   <div class="tabcontent" id="tab-gui-d38e44">This is plain old GUI...</div>
</div>

<p class="p">Here is another one.</p>

<div class="tab-win" id="tablinks-d38e56">
   <button class="tablinks" data-target="tab-bash-d38e56">bash</button>
   <button class="tablinks" data-target="tab-gui-d38e56">gui</button>
</div>

<div class="tabcontents" id="tabcontents-d38e56">
   <div class="tabcontent" id="tab-bash-d38e56">This is bash #2.</div>
   <div class="tabcontent" id="tab-gui-d38e56">This is plain old GUI..#2.</div>
</div>

</div>
它工作得很好。然而,我试图注意关注点的分离,并希望动态添加事件。我正试图通过以下方式实现这一点:

const tab = document.querySelectorAll(".tablinks");
const content = document.querySelectorAll(".tabcontent");

for (let i = 0; i < tab.length; i++) {
    let conId = tab[i].getAttribute('data-target');
    let conArray = Array.from(content);
    let con = conArray.find((c) => c.getAttribute('id') === conId);
    let c = con.getAttribute('id');
    tab[i].addEventListener('click', tabbedWindows(event,c), false);
}
我认为这是因为当函数尝试附加侦听器时,事件变量已经超出范围。这正是我从研究中得到的。长话短说,我被难住了,甚至不确定这是否是正确的方法。我想我有一些问题:

  • 为什么“event”在通过onclick属性传递时作为变量工作,而在作为参数传递到通过for循环调用的函数时不作为参数工作?我想我已经回答了这个问题,但也许有更博学的人可以提供更好的描述
  • 我的for循环似乎不必要地复杂。我是不是把事情搞得太复杂了?我猜是的

  • 非常感谢您的帮助。

    当您像这样声明事件处理程序时-
    tab[i]。addEventListener('click',tabbedWindows(event,c),false)
    ,则使用
    未定义的值调用
    选项卡窗口
    。由于
    evt
    undefined
    此语句-
    evt.currentTarget
    -抛出错误

    您需要向事件处理程序传递第二个参数,因为您需要从“数据目标”选项卡获取的内容id。但是,该选项卡是事件的目标,您可以在单击它时获取信息。我已经重构了代码,并删除了冗余

    const tabLinks=document.queryselectoral(“.tabLinks”);
    const tabContents=document.queryselectoral(“.tabcontent”);
    const activateTab=目标=>{
    const contentId=target.getAttribute('data-target');
    //使用class=“tabcontent”获取所有元素并隐藏它们,然后显示当前选项卡
    tabContents.forEach(tabContent=>{
    tabContent.style.display=tabContent.id==contentId?'block':'none';
    });
    //使用class=“tablinks”获取所有元素并删除类“active”
    tabLinks.forEach(tablink=>{
    tablink.classList.remove('active');
    });
    //向打开选项卡的按钮添加“活动”类
    target.classList.add('active');
    };
    常量选项卡窗口=evt=>{
    常数目标=evt.currentTarget;
    活化乙胺(靶);
    }
    document.querySelectorAll(“.tablinks”).forEach(制表符=>{
    tab.addEventListener('click',tabbedWindows,false);
    });
    activateTab(tabLinks[0])
    
    
    猛击
    桂
    这是bash。
    这是一个普通的老GUI。。。
    

    这里是另一个

    猛击 桂 这是bash#2。 这是一个朴素的老古董。
    当您像这样声明事件处理程序时-
    选项卡[i]。addEventListener('click',tabbedWindows(event,c),false)
    ,则使用
    未定义的值调用
    选项卡窗口
    。由于
    evt
    undefined
    此语句-
    evt.currentTarget
    -抛出错误

    您需要向事件处理程序传递第二个参数,因为您需要从“数据目标”选项卡获取的内容id。但是,该选项卡是事件的目标,您可以在单击它时获取信息。我已经重构了代码,并删除了冗余

    const tabLinks=document.queryselectoral(“.tabLinks”);
    const tabContents=document.queryselectoral(“.tabcontent”);
    const activateTab=目标=>{
    const contentId=target.getAttribute('data-target');
    //使用class=“tabcontent”获取所有元素并隐藏它们,然后显示当前选项卡
    tabContents.forEach(tabContent=>{
    tabContent.style.display=tabContent.id==contentId?'block':'none';
    });
    //使用class=“tablinks”获取所有元素并删除类“active”
    tabLinks.forEach(tablink=>{
    tablink.classList.remove('active');
    });
    //向打开选项卡的按钮添加“活动”类
    target.classList.add('active');
    };
    常量选项卡窗口=evt=>{
    常数目标=evt.currentTarget;
    活化乙胺(靶);
    }
    document.querySelectorAll(“.tablinks”).forEach(制表符=>{
    tab.addEventListener('click',tabbedWindows,false);
    });
    activateTab(tabLinks[0])
    
    
    猛击
    桂
    这是bash。
    这是一个普通的老GUI。。。
    

    这里是另一个

    猛击 桂 这是bash#2。 这是一个朴素的老古董。
    也许您应该先尝试一下:

    for (let i = 0; i < tab.length; i++) {
        tab[i].addEventListener('click', tabbedWindows, false);
    }
    

    也许你应该先尝试一下:

    for (let i = 0; i < tab.length; i++) {
        tab[i].addEventListener('click', tabbedWindows, false);
    }
    

    您需要使用
    tab[i].addEventListener('click',(event)=>tabbedWindows(event,c),false)-传递函数(带有事件参数)而不是函数calli的结果我喜欢使用data-attrib将稍后需要的信息附加到元素,这样就可以从事件处理程序的
    event.target.dataset.prop
    @Bergi Sheesh轻松访问它!我想这只是一个关注细节的问题。我想我还得学。谢谢@dandavis使用
    event.currentTarget.dataset.prop
    (或
    this.dataset.prop
    )仅供参考:永远不要使用。尤其是因为您似乎知道
    .queryselectoral()
    。您需要使用
    选项卡[i]。addEventListener('click',(event)=>选项卡窗口(event,c),false)-传递函数(带有事件参数)而不是函数calli的结果我喜欢使用data-attrib将稍后需要的信息附加到元素,这样就可以从事件处理程序的
    event.target.dataset.prop
    @Bergi Sheesh轻松访问它!我想这只是一个关注细节的问题。我想我还得学。谢谢@dandavis使用
    event.currentTarget.dataset.prop
    (或
    this.dataset.prop
    )仅供参考:永远不要使用。尤其是因为您似乎知道
    .querySelectorAll()
    。它看起来更像cu
    evt.currentTarget.className += " active";
    
    for (let i = 0; i < tab.length; i++) {
        tab[i].addEventListener('click', tabbedWindows, false);
    }
    
    function tabbedWindows(event) { 
    
         let conId = event.currentTarget.getAttribute('data-target');
         let conArray = Array.from(content);
         let con = conArray.find((c) => c.getAttribute('id') === conId);
         let c = con.getAttribute('id');
    
         // and then rest of your code goes here
    
    }