Не удается прочитать свойства null (чтение «querySelectorAll») в строке 189

Это указывает на эту строку:

wrappers = container.querySelectorAll(".wrap");

Нажатие кнопки выхода вызывает ошибку.

Нажатие на кнопку выхода должно удалить игрока после нажатия синей кнопки воспроизведения.

Чтобы протестировать код jsitor, нажмите «Выполнить, а не обновлять».

код https://jsitor.com/KZMNnkSf5

https://jsfiddle.net/e631o2rq/

Как это фиксируется в коде?

  function removePlayerHandler(evt) {
    const el = evt.target;
    let container = el.closest(".container");
    let wrappers;
    if (container) { //if multiple players
      wrappers = container.querySelectorAll(".remove .wrap");
    } else { //if single player
      container = el.closest(".remove");
      wrappers = container.querySelectorAll(".wrap");
    }
    wrappers.forEach(function (wrapper) {
      if (wrapper.player) {
        removePlayer(wrapper);
      }
    });
  }

Раньше это выглядело так:

  function removePlayerHandler(evt) {
    const el = evt.target;
    const container = el.closest(".container");
    const wrapper = container.querySelector(".wrap");
    if (wrapper.player) {
      return removePlayer(wrapper);
    }
  }



        </div>
      </div>
    </div>
  </div>
</div>

 <div class = "button-container">
<button class = "exit" type = "button"></button>
<button class = "exit exitpPage2" type = "button"></button>
<button class = "exit exitpPage3" type = "button"></button>
</div>

Из сообщения об ошибке довольно ясно, что el.closest(".remove") — это null.

Sebastian Simon 15.11.2022 13:20

Как исправить это в коде?

Eve Ninnall 15.11.2022 13:20

В настоящее время ваш код предполагает, что элемент находится где-то «под» элементом с классом «удалить». По-видимому, это не всегда так, поэтому вам придется либо исправить свой HTML, либо убедиться, что опубликованный код проверяет, возвращает ли этот .closest() вызов null.

Pointy 15.11.2022 13:21

Если он выше этого, как это будет исправлено в коде? Что бы изменить в javascript, чтобы справиться с этим? Что изменится в javascript, чтобы он мог смотреть вверх, а не вниз?

Eve Ninnall 15.11.2022 13:22
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
4
123
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не совсем уверен, что вы пытаетесь сделать здесь, но это выглядит немного сложно. Я мог бы предложить просто сделать вещи намного проще.

Вот идея: https://jsitor.com/JOlxKAhhbL

Код также прикреплен ниже, чтобы его можно было прочитать, но из-за песочницы iframes в stackoverflow он не может загрузить проигрыватель YouTube, вместо этого загрузите ссылку jsitor выше.

// Note: move data-id to `.wrap` element

const DEFAULT_PLAY_OPTIONS = {
  events: {
    onReady: function onPlayerReady(event) {
      event.target.playVideo()
    },
    onStateChange: function onPlayerStateChange(event) {
      // whatever you'd like
    }
  },
  height: 360,
  host: "https://www.youtube-nocookie.com",
  playerVars: {
    autoplay: 1,
    controls: 1,
    disablekb: 1,
    fs: 0,
    iv_load_policy: 3
  },
  width: 640
}
const removeAllPlayers = () => {
  for (const wrapperEle of [...document.querySelectorAll('.embed-youtube.active')]) {
    wrapperEle.querySelector('iframe').remove()
    const videoEle = document.createElement('div')
    videoEle.classList.add('video', 'embed-youtube')
    wrapperEle.append(videoEle)
    const curtainEle = wrapperEle.closest('.curtain,.curtain1')
    curtainEle.classList.remove('slide')
    wrapperEle.classList.remove('active')
  }
}
const createAndPlayVideo = (playBtnEle) => {
  const curtainEle = playBtnEle.closest('.curtain,.curtain1')
  const wrapperEle = playBtnEle.closest('.wrap')
  const embedYoutubeEle = wrapperEle.querySelector('.video')
  const playOptions = {...DEFAULT_PLAY_OPTIONS}
  playOptions.videoId = wrapperEle.getAttribute('data-id')
  const player = new YT.Player(embedYoutubeEle, playOptions)
  curtainEle.classList.add('slide')
  wrapperEle.classList.add('active')
}
const bindPlayers = () => {
  for (const playBtn of [...document.querySelectorAll('.playa')]) {
    playBtn.addEventListener('click', function(clickEvent) {
      createAndPlayVideo(clickEvent.target)
    })
  }
  for (const stopBtn of [...document.querySelectorAll('.exit')]) {
    stopBtn.addEventListener('click', function(clickEvent) {
      removeAllPlayers()
    })
  }
}
const init = () => {
  bindPlayers()
}

init()
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  background: #302b63;
}

.button-container {
  display: flex;
  flex-wrap: wrap;
  min-height: 100%;
  margin: auto;
  justify-content: center;
  align-content: center;
  width: 290px;
  gap: 10px;
  background: green;
}

.container2 .container {
  background: teal;
}

.container3 .container {
  background: green;
}

.container1 {
  position: absolute;
  left: 0;
  right: 0;
  min-height: 100%;
  min-width: 255px;
  display: flex;
  padding: 8px 8px;
}

.curtain1 {
  flex: 1 0 0;
  margin: auto;
  max-width: 640px;
  border: 21px solid;
  border-radius: 12px;
  border-color: #000 #101010 #000 #101010;
  position: relative;
}

.ratio-keeper {
  position: relative;
  height: 0;
  padding-top: 56.25%;
  margin: auto;
  overflow: hidden;
}

.container {
  position: absolute;
  left: 0;
  right: 0;
  min-height: 100%;
  padding: 8px 8px;
}

.curtain {
  margin: auto auto 40px;
  max-width: 640px;
  border: 21px solid;
  border-radius: 12px;
  border-color: #000 #101010 #000 #101010;
  position: relative;
}

.embed-youtube iframe,
.embed-youtube .embed-youtube-play,
.embed-youtube .embed-youtube-play::before {
  position: absolute;
}

.embed-youtube iframe {
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
}

.embed-youtube .embed-youtube-play {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  margin: auto;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  cursor: pointer;
  border: 9px solid blue;
  background: transparent;
  filter: drop-shadow(3px 3px 3px #000000b3);
  z-index: 1;
}

.embed-youtube-play::before {
  content: "";
  width: 0;
  height: 0;
  border-top: 20px solid transparent;
  border-bottom: 20px solid transparent;
  border-left: 27px solid blue;
  transform: translateX(4px);
}

.embed-youtube-play:hover {
  box-shadow: 0 0 0 5px rgba(43, 179, 20, 0.5);
}

.embed-youtube-play:focus {
  outline: 0;
  box-shadow: 0 0 0 5px rgba(0, 255, 255, 0.5);
}

.embed-youtube.active .embed-youtube-play {
  display: none;
}

@keyframes rotate {
  0% {
    transform: rotate(0deg);
  }
  99.9% {
    border-color: red transparent red transparent;
    pointer-events: none;
  }
  100% {
    transform: rotate(360deg);
    border-color: blue;
  }
}

@keyframes triangle {
  0% {
    opacity: 0;
  }
  99.9% {
    opacity: 0;
  }
  100% {
    border-left-color: blue;
    opacity: 1;
  }
}

.exit {
  position: absolute;
  top: auto;
  bottom: -47.63px;
  margin: auto;
  right: 0;
  left: 0;
  width: 47px;
  height: 47px;
  cursor: pointer;
  border-radius: 100%;
  background: transparent;
  border: 5px solid red;
  box-sizing: border-box;
  clip-path: circle(50%);
}

.exit::before,
.exit::after {
  content: "";
  background-color: red;
  width: 47px;
  height: 5px;
  position: absolute;
  top: 0px;
  left: -5px;
  right: 0;
  bottom: 0;
  margin: auto;
}

.exit::before {
  transform: rotate(45deg);
}

.exit::after {
  transform: rotate(-45deg);
}

.exit.exitpPage2 {
  position: absolute;
  top: auto;
  bottom: -47.63px;
  margin: auto;
  right: 200px;
  left: 0;
  border: 5px solid blue;
}

.exit.exitpPage2::before,
.exit.exitpPage2::after {
  background-color: blue;
}

.exit.exitpPage3 {
  position: absolute;
  top: auto;
  bottom: -47.63px;
  margin: auto;
  right: 0px;
  left: 200px;
  border: 5px solid purple;
}

.exit.exitpPage3::before,
.exit.exitpPage3::after {
  background-color: purple;
}

.hide {
  display: none;
}
<div class = "container1">
  <div class = "curtain1 remove">
    <div class = "ratio-keeper">
      <div class = "video-one"></div>
      <div class = "wrap embed-youtube" data-id = "djV11Xbc914">
        <div class = "video embed-youtube ">
        </div>
        <button class = "playa cover embed-youtube-play" type = "button"></button>
      </div>
    </div>

  </div>
</div>
<div class = "container2 hide">
  <div class = "container ">
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-two"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playb cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-three"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playc cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-four"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playd cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-five"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playe cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-six"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playf cover embed-youtube-play" type = "button"></button>
        </div>
      </div>

    </div>
  </div>
</div>
<div class = "container3 hide">
  <div class = "container ">
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-seven"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playg cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-eight"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playh cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-nine"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playi cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-ten"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playj cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
    <div class = "curtain remove">
      <div class = "ratio-keeper">
        <div class = "video-eleven"></div>
        <div class = "wrap embed-youtube">
          <div class = "video embed-youtube" data-id = "djV11Xbc914">
          </div>
          <button class = "playk cover embed-youtube-play" type = "button"></button>
        </div>
      </div>
    </div>
  </div>
</div>

<div class = "button-container">
  <button class = "exit" type = "button"></button>
  <button class = "exit exitpPage2" type = "button"></button>
  <button class = "exit exitpPage3" type = "button"></button>
</div>
<script src = "https://www.youtube.com/player_api"></script>

Этот код настроен аналогично, с контейнером внизу. Сможете ли вы заставить это работать? Этот код, который я пытаюсь заставить работать, имеет кнопки воспроизведения внизу внутри своего собственного контейнера. jsitor.com/MIYiywN4HC / jsfiddle.net/kxhyLdr8 Что странно в этом коде, так это то, что после нажатия на кнопки не появляются ошибки, хотя они должны быть. Вот демонстрационный код, который работает с кнопками воспроизведения не внутри их собственного контейнера. jsfiddle.net/24xf0avp

Eve Ninnall 16.11.2022 06:07

Никто не смог понять, как это можно сделать, заставив кнопки воспроизведения работать внутри их собственного контейнера.

Eve Ninnall 16.11.2022 06:08

Я честно с трудом понимаю, чего вы хотите. Я думаю, вы пытаетесь сформулировать множество разных проблем или пытаетесь достичь чего-то, что, вероятно, выходит за рамки вашего текущего уровня навыков. Для того, чтобы все могли помочь (и мы будем), пожалуйста, постарайтесь четко определить, чего именно вы пытаетесь достичь. Попробуйте использовать каркасный инструмент, такой как wireframe.cc, чтобы дать нам представление о том, чего вы хотите достичь. У вас много javascript-кода и html-разметки, но это очень запутывает даже некоторых из нас с опытом. Спасибо

dangarfield 16.11.2022 09:51

Вот рабочий демонстрационный код только с 1 кнопкой. jsitor.com/Qer_1Oi9Jv / jsfiddle.net/1bmrwuzn Вот битый код только с 1 кнопкой. jsitor.com/D38vgjs3g / jsfiddle.net/gt57k29h

Eve Ninnall 16.11.2022 10:02

Возможно, мне просто нужно расширить код javascript, чтобы он достиг внутреннего узла html. Если да, то как это сделать? Это было доведено до моего сведения: «в событии нажатия кнопки он, вероятно, захватывает родительский элемент вместо целевого элемента?»

Eve Ninnall 16.11.2022 10:03

Еще раз, пожалуйста, позвольте мне быть ясным. Можете ли вы сказать, чего вы хотите? «Вот рабочая демонстрация» интерпретируется как «Я решил свою проблему». Но я точно не знаю, чего ты хочешь. Можете ли вы нарисовать каркас или диаграмму, которая ясно показывает ожидаемый результат, пожалуйста.

dangarfield 16.11.2022 10:06

Единственная разница между рабочим и нерабочим примером — дополнительный слой HTML. В других частях кода ничего не трогали.

Eve Ninnall 16.11.2022 10:06

Мой инструктор сказал мне, что кнопки воспроизведения должны находиться внутри своего собственного контейнера. Это помогает? Я пытаюсь заставить код работать, когда кнопки находятся внутри своего собственного контейнера. Код, который сломан, я пытаюсь исправить, чтобы он работал.

Eve Ninnall 16.11.2022 10:07

Это кнопка воспроизведения внутри собственного контейнера: <div class = "playButtonContainer"> <button class = "playa cover" type = "button" aria-label = "Open"></button> </div>

Eve Ninnall 16.11.2022 10:09

Пожалуйста, нарисуйте то, что вы хотите. например, что вы определяете как «контейнер». Пожалуйста, без лишних слов, просто несколько диаграмм, показывающих желаемый результат всех нарисованных элементов (большая кнопка воспроизведения, 3 кнопки выхода, черная рамка вокруг видео, само видео, зеленый фон и все). Нарисуйте отдельные диаграммы, чтобы показать, что должно быть видно на каждом этапе, и что происходит, чтобы запустить этот этап (например, каждый щелчок). Спасибо

dangarfield 16.11.2022 10:12

Давайте продолжим обсуждение в чате.

Eve Ninnall 16.11.2022 10:38

Привет, можешь вернуться в чат, пожалуйста? У меня работает код. Но у меня было несколько вопросов, чтобы задать вам о том, что я сделал.

Eve Ninnall 17.11.2022 15:39

Другие вопросы по теме