1

目标:仅在 ajax 调用(添加或删除标签)后重新加载 div,而不会丢失重新加载的 div 上的事件侦听器。使用insertAdjacentHTML似乎不是最佳的。

前端:我有一个带有 ul/li 标签的侧边栏。有一个添加/创建标签的模式;每个标签旁边都有一个图标“X”,可以在点击时将其删除。

<ul>
  <li><span>A</span><span class=li-untag>X</span> 
  <li><span>B</span><span class=li-untag>X</span> 
  <li><span>C</span><span class=li-untag>X</span> 
  <li><span>D</span><span class=li-untag>X</span>
</ul>

我失败的设置是

  1. 向 php 后端发送 ajax (fetch) 调用以添加或删除标签

  2. 如果没有错误,后端会为文章发送一个更新的、twig 格式的标签列表

  3. 用 . 更新了 div innerHTML

更新将丢失列表的innerHTML所有事件侦听器(例如单击 X 时删除标记),直到真正刷新页面。我试图在 ajax 调用之后运行 addeventlisteners,但它没有用。

我当前的设置基于以前的 SO 答案(见下文)使用insertAdjacentHTML. 这(有点)有效,但它很笨重。

  • 删除标签不是插入问题,我所能想到的就是在点击时隐藏标签,直到页面刷新。
  • 添加标签是将新标签附加insertAdjacentHTML到列表中,但它不再按字母顺序排列,我必须使用一些 hacky javascript 来格式化输出以匹配现有列表。

我真的更喜欢让 php 为 div 发送一个完整的更新和格式化列表。

有什么建议可以用更优雅的方式在 vanilla js 中执行此操作吗?

仅供参考:我依赖的主要答案:
为什么事件侦听器在使用 element.innerHTML 后会停止工作?
是否可以在不破坏后代事件侦听器的情况下附加到 innerHTML?
如果移除了一个 DOM 元素,它的监听器是否也会从内存中移除?
JS eventListener点击消失

编辑:监听器附加到“li-untag”类

编辑 2:回答更多代码的评论请求。这是使用原子 ajax 库删除标签的内容:

for(let liUntag of document.querySelectorAll('.li-untag')){
liUntag.addEventListener("click", () => altUntag(liUntag))};

const altUntag = (el) => {
    atomic("/tags", {
        method: 'POST',
        data: {
            type: 'untag',
            slug: el.getAttribute('data-slug'),
            tag: el.getAttribute('data-untag')
        }
    }).then(function (response) {
        el.closest('li').style.display = 'none';
        console.log(response.data); // xhr.responseText
        console.log(response.xhr);  // full response
    })
    .catch(function (error) {
        console.log(error.status); // xhr.status
        console.log(error.statusText); // xhr.statusText
    });
};
4

1 回答 1

1

此类问题的最佳解决方案是使用事件委托将单个侦听器附加到 ,ul而不是将多个侦听器附加到每个侦听器li-untag

document.querySelector('ul').addEventListener('click', ({ target }) => {
  if (target.matches('.li-untag')) {
    target.closest('li').remove();
  }
});

如果您不想这样做并希望在每个li-untag元素上保留一个侦听器,则可以插入新的 HTML,然后对<li>s 进行排序,并将侦听器附加到每个新的li-untag

const addListeners = () => {
  document.querySelectorAll('.li-untag').forEach((span) => {
    span.addEventListener('click', ({ target }) => {
      target.closest('ul').remove();
    });
  });
};

// on document load:
addListeners();

// after inserting new HTML:
const lis = [...document.querySelectorAll('ul li')];
lis.sort((a, b) => a.children[0].textContent.localeCompare(b.children[0].textContent));
const ul = document.querySelector('ul');
lis.forEach((li) => {
  ul.appendChild(li);
});
addListeners();
于 2019-04-27T19:28:51.170 回答