Как решить проблему с addEventListener: невозможно прочитать свойство 'currentTarget' из неопределенного - PullRequest
0 голосов
/ 22 октября 2019

Я новичок в 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>

Я собрал эту функцию вместе.

function tabbedWindows(evt, env) {
  // Declare all variables
  var i, tabcontent, tablinks;

  // Get all elements with class="tabcontent" and hide them
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }

  // Get all elements with class="tablinks" and remove the class "active"
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }

  // Show the current tab, and add an "active" class to the button that opened the tab
  document.getElementById(env).style.display = "block";
  evt.currentTarget.className += " active";
}

Если я добавлю атрибут onclick непосредственно к элементам кнопки, например, так:

onclick="tabbedWindows(event,'content-id')"

, он прекрасно работает. Тем не менее, я стараюсь разделить проблемы и хочу добавить событие динамически. Я пытаюсь сделать это со следующим:

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);
}

Это не работает из-за следующей ошибки: main.js: 23 Uncaught TypeError: Невозможно прочитать свойство 'currentTarget' из неопределенного. Строка, в которой происходит сбой:

evt.currentTarget.className += " active";

Я думаю, что причина этого к тому времени, когда функция пытается подключить слушателя, переменная события уже выходит за рамки. Это именно то, что я смог почерпнуть из исследований. В общем, я в тупике и даже не уверен, что это правильный подход. Я думаю, у меня есть несколько вопросов:

  1. Почему «событие» работает как переменная, когда передается через атрибут onclick, а не когда передается в качестве параметра функции, вызванной через цикл for? Я думаю, что я уже ответил на этот вопрос, но, возможно, кто-то более знающий может дать лучшее описание.
  2. Мой цикл for кажется излишне запутанным. Я здесь все усложняю? Я предполагаю «да».

Любая помощь приветствуется.

Ответы [ 2 ]

2 голосов
/ 22 октября 2019

Когда вы объявляете обработчик событий следующим образом - tab[i].addEventListener('click', tabbedWindows(event,c), false);, вы вызываете tabbedWindows со значениями undefined. Поскольку evt равно undefined, этот оператор - evt.currentTarget - выдает ошибку.

Вам необходимо передать второй параметр обработчику событий, потому что вы хотите получить идентификатор содержимого, который вы берете с вкладки `данные-мишень». Тем не менее, вкладка является целью события, и вы можете получить информацию, нажав на нее. Я переработал код и удалил избыточность.

const tabLinks = document.querySelectorAll(".tablinks");
const tabContents = document.querySelectorAll(".tabcontent");

const activateTab = target => {
  const contentId = target.getAttribute('data-target');

  // Get all elements with class="tabcontent" and hide them, and show the current tab
  tabContents.forEach(tabContent => {
    tabContent.style.display = tabContent.id === contentId ? 'block' : 'none';
  });

  // Get all elements with class="tablinks" and remove the class "active"
  tabLinks.forEach(tablink => {
    tablink.classList.remove('active');
  });

  // Add an "active" class to the button that opened the tab
  target.classList.add('active');
};

const tabbedWindows = evt => {
  const target = evt.currentTarget;

  activateTab(target);
}

document.querySelectorAll(".tablinks").forEach(tab => {
  tab.addEventListener('click', tabbedWindows, false);
});

activateTab(tabLinks[0]);
<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>

Предыдущий ответ:

Вы можете использовать карри для получения env и возврата новой функции, котораяожидает объекта события:

/** get env and return a new function that will be called with the event object **/
const tabbedWindows = env => evt => {
  // Declare all variables
  var i, tabcontent, tablinks;

  // Get all elements with class="tabcontent" and hide them
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }

  // Get all elements with class="tablinks" and remove the class "active"
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }

  // Show the current tab, and add an "active" class to the button that opened the tab
  document.getElementById(env).style.display = "block";
  evt.currentTarget.className += " active";
}

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(c), false); // call tabbedWindows with c
}
<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>
0 голосов
/ 22 октября 2019

Может быть, вам следует сначала попробовать сделать это:

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

, и в вашей функции tabbedWindows вы можете добавить эти строки

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

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...