重新加载后,切换不适用于 DOM 渲染的 HTML 元素

发布于 2025-01-18 10:08:53 字数 3143 浏览 4 评论 0原文

我正在制作一个天气应用程序,我想单击一个按钮在英制和公制之间进行转换。我还有一个搜索栏,当我输入一个位置时,会出现一个下拉菜单,我可以单击其中一项,HTML 页面将重新加载新信息。

在单击任何下拉项(在页面上具有初始值)之前,切换按钮可以正常工作。但是,当我单击下拉项并重新加载页面后,该按钮适用于我直接写入 .html 文件的 HTML 元素。对于我通过 DOM 写入 HTML 的其他元素,它不起作用。

相关代码如下。

async function init (name) {
  await fetchCurrentData(name)

  const forecastHoursList =  await hoursList(name)
  document.querySelector('.forecast ul').innerHTML = renderHourlyForecast(forecastHoursList)

  const forecastDailyList =  await dailyList(name)
  document.querySelector('.future ul').innerHTML = renderDailyForecast(forecastDailyList)
}


// initial value
await init('Miami')


// toggle function below
const button = document.querySelector('button')
const hidden = document.querySelectorAll('span.hidden')
const visible = document.querySelectorAll('span.toggle')

button.addEventListener('click', event => {
  hidden.forEach(el => {
    el.classList.toggle('hidden')
    el.classList.toggle('toggle')
  })
  visible.forEach(el => {
    el.classList.toggle('hidden')
    el.classList.toggle('toggle')
  })


//Render data into HTML elements
const renderHourlyForecast = (forecastHoursList) => {
  const renderedForecastList = forecastHoursList.map((el) => {
    return `
    <div>
      <li>
        <ul>
          <li><h4>${el[0]}</h4></li>
          <li><img src="${el[1]}"></li>
          <li><span class="toggle" style="float: left">Temp °C</span><span class="hidden" style="float: left">Temp °F</span><h4 class="temp">${el[2]}</h4></li>
          <li><span class="toggle" style="float: left">Feels °C</span><span class="hidden" style="float: left">Feels °F</span><h4 class="temp">${el[3]}</h4></li>
          <li><span class="toggle" style="float: left">Wind kph</span><span class="hidden" style="float: left">Wind mph</span><h4 class="windspeed">${el[4]}</h4></li>
          <li><span style="float: left">Cloud cover</span><h4>${el[5]}%</h4></li>
          <li><span style="float: left">Precip chance</span><h4>${el[6]}%</h4></li>
        </ul>
      </li>
    </div>
    `
  }).join('')
  return renderedForecastList
}


//Searchbar input event below
const onInput = async event => {
  const cityList = await autoComplete(event.target.value)

  if(!cityList.length) {
    dropdown.classList.remove('is-active');
    return
  }

  resultsWrapper.innerHTML = ''
  dropdown.classList.add('is-active');

  for(let list of cityList) {
    const option = document.createElement('a')
    option.classList.add('dropdown-item')
    option.innerHTML = renderOption(list)

    //Dropdown click event below
    option.addEventListener('click', async () => {
      dropdown.classList.remove('is-active');
      search.value = list[0];
      await init(list[0])
    });

  resultsWrapper.appendChild(option)
  }
}

I'm making a weather app and I want to click a button to convert between imperial and metric. I also have a search bar and when I enter a location, a dropdown menu would appear and I can click on one of the items and the HTML page would reload with new info.

Before clicking on any dropdown item (with initial values on the page), the toggle button works fine. But after I click on a dropdown item and the page reloads, the button works only for HTML elements that I wrote directly into the .html file. For the other elements that I wrote into HTML through DOM, it doesn't work.

Relevant code below.

async function init (name) {
  await fetchCurrentData(name)

  const forecastHoursList =  await hoursList(name)
  document.querySelector('.forecast ul').innerHTML = renderHourlyForecast(forecastHoursList)

  const forecastDailyList =  await dailyList(name)
  document.querySelector('.future ul').innerHTML = renderDailyForecast(forecastDailyList)
}


// initial value
await init('Miami')


// toggle function below
const button = document.querySelector('button')
const hidden = document.querySelectorAll('span.hidden')
const visible = document.querySelectorAll('span.toggle')

button.addEventListener('click', event => {
  hidden.forEach(el => {
    el.classList.toggle('hidden')
    el.classList.toggle('toggle')
  })
  visible.forEach(el => {
    el.classList.toggle('hidden')
    el.classList.toggle('toggle')
  })


//Render data into HTML elements
const renderHourlyForecast = (forecastHoursList) => {
  const renderedForecastList = forecastHoursList.map((el) => {
    return `
    <div>
      <li>
        <ul>
          <li><h4>${el[0]}</h4></li>
          <li><img src="${el[1]}"></li>
          <li><span class="toggle" style="float: left">Temp °C</span><span class="hidden" style="float: left">Temp °F</span><h4 class="temp">${el[2]}</h4></li>
          <li><span class="toggle" style="float: left">Feels °C</span><span class="hidden" style="float: left">Feels °F</span><h4 class="temp">${el[3]}</h4></li>
          <li><span class="toggle" style="float: left">Wind kph</span><span class="hidden" style="float: left">Wind mph</span><h4 class="windspeed">${el[4]}</h4></li>
          <li><span style="float: left">Cloud cover</span><h4>${el[5]}%</h4></li>
          <li><span style="float: left">Precip chance</span><h4>${el[6]}%</h4></li>
        </ul>
      </li>
    </div>
    `
  }).join('')
  return renderedForecastList
}


//Searchbar input event below
const onInput = async event => {
  const cityList = await autoComplete(event.target.value)

  if(!cityList.length) {
    dropdown.classList.remove('is-active');
    return
  }

  resultsWrapper.innerHTML = ''
  dropdown.classList.add('is-active');

  for(let list of cityList) {
    const option = document.createElement('a')
    option.classList.add('dropdown-item')
    option.innerHTML = renderOption(list)

    //Dropdown click event below
    option.addEventListener('click', async () => {
      dropdown.classList.remove('is-active');
      search.value = list[0];
      await init(list[0])
    });

  resultsWrapper.appendChild(option)
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倾城°AllureLove 2025-01-25 10:08:53

该按钮仅适用于我直接写入.html文件中的HTML元素。对于我通过DOM写入HTML的其他元素,它不起作用。

之所以发生这种情况,是因为您使用InnerHtml+=作为dom主要元素的子树已完全重建,事件处理程序被销毁。更好地使用event.target检查单击元素是否是下拉元素。

例如

const fruits = ['Pineapple', 'Coconut', 'Mango'],
  list = document.querySelector('ul');

fruits.forEach(fruit => {
  list.innerHTML += `<li>${fruit}</li>`
})

list.addEventListener('click', e => {
  if (e.target.tagName.toLowerCase() === 'li')
    e.target.innerText = e.target.innerText.split('').reverse().join('');
})
<ul>
  <li>Apple</li>
</ul>

The button works only for HTML elements that I wrote directly into the .html file. For the other elements that I wrote into HTML through DOM, it doesn't work.

This is happening because you used innerHTML+= as the DOM Subtree of the main element is completely reconstructed, the event handlers are destroyed. Better use the event.target to check whether the element clicked is a dropdown element or not.

For example

const fruits = ['Pineapple', 'Coconut', 'Mango'],
  list = document.querySelector('ul');

fruits.forEach(fruit => {
  list.innerHTML += `<li>${fruit}</li>`
})

list.addEventListener('click', e => {
  if (e.target.tagName.toLowerCase() === 'li')
    e.target.innerText = e.target.innerText.split('').reverse().join('');
})
<ul>
  <li>Apple</li>
</ul>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文