【问题标题】:Filter Data When Click the Tab单击选项卡时过滤数据
【发布时间】:2021-04-15 13:50:36
【问题描述】:

我有两个输入(标题和状态)和一个提交按钮。当我单击提交按钮时,我将输入值添加到表中。但是,表格有 3 个按钮;全部,活动且已完成。我要做的是当我单击“活动”或“已完成”按钮时,该按钮应该处于活动状态并根据列表中的“状态”值过滤数据。 (默认情况下应选择所有按钮并显示所有数据,无论其状态如何)

例如,在下图中,如果我单击“已完成”选项卡,该选项卡应该处于活动状态并且只显示 Cook。

这是我几天前尝试解决的 DOM 挑战,但仍然无法解决。我不允许更改 HTML 中的任何内容。只有原生 JavaScript。

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      href="https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic.bundle.css"
      rel="stylesheet"
    />
    <script
      type="module"
      src="https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.esm.js"
    ></script>
    <script
      nomodule
      src="https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.js"
    ></script>

    <script src="https://cdn.jsdelivr.net/npm/h8k-components@latest/dist/h8k-components.js"></script>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/h8k-design@latest/dist/index.css"
    />

    <link rel="stylesheet" href="./styles.css" />
    <script type="module" src="./index.js"></script>

    <title>Document</title>
  </head>
  <body>
    <div id="root">
      <h8k-navbar header="Notes"></h8k-navbar>
      <div class="layout-column align-items-center justify-content-start">
        <section
          class="layout-row align-items-center justify-content-center mt-30"
        >
          <input
            data-testid="input-note-name"
            type="text"
            class="large mx-8"
            placeholder="Note Title"
          />
          <input
            data-testid="input-note-status"
            type="text"
            class="large mx-8"
            placeholder="Note Status"
          />
          <button class="" data-testid="submit-button">Add Note</button>
        </section>
        <div class="mt-50">
          <ul class="tabs">
            <li class="tab-item slude-up-fade-in" data-testid="allButton">
              All
            </li>
            <li class="tab-item slude-up-fade-in" data-testid="activeButton">
              Active
            </li>
            <li class="tab-item slude-up-fade-in" data-testid="completedButton">
              Completed
            </li>
          </ul>
        </div>
        <div class="card w-40 pt-30 pb-8">
          <table>
            <thead>
              <tr>
                <th>Title</th>
                <th>Status</th>
              </tr>
            </thead>
            <tbody data-testid="noteList"></tbody>
          </table>
        </div>
      </div>
    </div>
  </body>
</html>

CSS

.tabs {
  list-style: none;
  display: flex;
  margin: 0;
  padding: 0;
}

.tabs .tab-item {
  min-width: 88px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  position: relative;
  cursor: pointer;
  padding: 20px 16px;
  color: var(--heading-color);
}

.tabs .tab-item::before {
  content: '';
  position: absolute;
  top: 0;
  width: 100%;
  height: 2px;
  background: var(--primary-color);
  opacity: 0;
  transition: opacity 0.3s ease-in-out;
}

.tabs .tab-item:active {
  background: #fff;
  position: relative;
  color: black;
}

.tabs .tab-item:active::before {
  opacity: 1;
}

table tbody tr td {
  font-weight: bold;
  font-size: 16px;
  height: 21px;
  padding: 1.6rem;
}

JavaScript

const nameInput = document.querySelector('[data-testid="input-note-name"]');
const statusInput = document.querySelector('[data-testid="input-note-status"]');
const submitButton = document.querySelector('[data-testid="submit-button"]');
const allButton = document.querySelector('[data-testid="allButton"]');
const activeButton = document.querySelector('[data-testid="activeButton"]');
const completedButton = document.querySelector(
  '[data-testid="completedButton"]'
);
const noteList = document.querySelector('[data-testid="noteList"]');
const tabs = document.querySelector('.tabs');

submitButton.addEventListener('click', () => {
  console.log('Hey');
  const titleNode = document.createTextNode(nameInput.value);
  const statusNode = document.createTextNode(statusInput.value);
  const trEl = document.createElement('tr');
  const tdEl = document.createElement('td');
  const tdEl2 = document.createElement('td');

  trEl.appendChild(tdEl);
  tdEl.appendChild(titleNode);
  trEl.appendChild(tdEl2);
  tdEl2.appendChild(statusNode);
  noteList.appendChild(trEl);
});

【问题讨论】:

  • 一种方法是修改要隐藏的行的css并将它们设置为display: none

标签: javascript dom


【解决方案1】:

以防万一您尝试创建尽可能多的代码行,而您确实希望用尽可能多的变量填充全局空间,那么也许以下内容也适用于您:

const tb=document.querySelector("[data-testid=noteList]");

document.querySelector("button").onclick=ev=>    // add an entry
 tb.innerHTML+="<tr><td>"
  +[...ev.target.parentNode.children]
    .filter(e=>e.tagName==="INPUT")
    .map(e=>e.value)
    .join("</td><td>")+"</td></tr>";
    
document.querySelector("ul.tabs").onclick=ev=>{  // filter buttons
 if (ev.target.tagName==="LI"){
  let sel=ev.target.textContent.trim().toLowerCase();
  [...tb.children].forEach(tr=>tr.style.display=
    sel=="all" || sel===tr.children[1].textContent.trim().toLowerCase()
    ? "" : "none"  )
}}
.tabs {
  list-style: none;
  display: flex;
  margin: 0;
  padding: 0;
}

.tabs .tab-item {
  min-width: 88px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  position: relative;
  cursor: pointer;
  padding: 20px 16px;
  color: var(--heading-color);
}

.tabs .tab-item::before {
  content: '';
  position: absolute;
  top: 0;
  width: 100%;
  height: 2px;
  background: var(--primary-color);
  opacity: 0;
  transition: opacity 0.3s ease-in-out;
}

.tabs .tab-item:active {
  background: #fff;
  position: relative;
  color: black;
}

.tabs .tab-item:active::before {
  opacity: 1;
}

table tbody tr td {
  font-weight: bold;
  font-size: 16px;
  height: 1px;
  padding: 2px 20px;
}
<div id="root">
  <h8k-navbar header="Notes"></h8k-navbar>
  <div class="layout-column align-items-center justify-content-start">
    <section class="layout-row align-items-center justify-content-center mt-30">
      <input data-testid="input-note-name" type="text" class="large mx-8" placeholder="Note Title" />
      <input data-testid="input-note-status" type="text" class="large mx-8" placeholder="Note Status" />
      <button class="" data-testid="submit-button">Add Note</button>
    </section>
    <div class="mt-50">
      <ul class="tabs">
        <li class="tab-item slude-up-fade-in" data-testid="allButton">
          All
        </li>
        <li class="tab-item slude-up-fade-in" data-testid="activeButton">
          Active
        </li>
        <li class="tab-item slude-up-fade-in" data-testid="completedButton">
          Completed
        </li>
      </ul>
    </div>
    <div class="card w-40 pt-30 pb-8">
      <table>
        <thead>
          <tr>
            <th>Title</th>
            <th>Status</th>
          </tr>
        </thead>
        <tbody data-testid="noteList"></tbody>
      </table>
    </div>
  </div>
</div>

我还冒昧地删除了 &lt;td&gt; 元素 (padding: 1.6rem) 周围的一些随机空白,因为我宁愿看到 content 而不是空白。

【讨论】:

  • 看起来有点复杂,但谢谢。
【解决方案2】:

我使用了一些全局变量和常量来跟踪当前选择了哪个type

let typeSelected = "all";
const allNotes = [];

您需要在所有 3 个按钮上添加 addEventListener,即 all, active, completed,以便在单击时更改类型。

我只为所有功能添加了一个函数showDataInDOM()

const nameInput = document.querySelector('[data-testid="input-note-name"]');
const statusInput = document.querySelector('[data-testid="input-note-status"]');
const submitButton = document.querySelector('[data-testid="submit-button"]');
const allButton = document.querySelector('[data-testid="allButton"]');
const activeButton = document.querySelector('[data-testid="activeButton"]');
const completedButton = document.querySelector(
  '[data-testid="completedButton"]'
);
const noteList = document.querySelector('[data-testid="noteList"]');
const tabs = document.querySelector(".tabs");

// APP STATE
const buttons = [allButton, activeButton, completedButton];
let typeSelected = "all";
const allNotes = [];

function showDataInDOM() {
  const fragment = document.createDocumentFragment();
  let filteredNotes = [];
  if (typeSelected !== "all")
    filteredNotes = allNotes.filter((note) => note.status === typeSelected);
  else filteredNotes = allNotes;

  filteredNotes.forEach(({
    title,
    status
  }) => {
    const tr = document.createElement("tr");
    const td = document.createElement("td");
    const td2 = document.createElement("td");

    td.appendChild(document.createTextNode(title));
    td2.appendChild(document.createTextNode(status));
    tr.appendChild(td);
    tr.appendChild(td2);
    fragment.appendChild(tr);
  });
  noteList.innerHTML = "";
  noteList.appendChild(fragment);
}

submitButton.addEventListener("click", () => {
  const title = nameInput.value;
  const status = statusInput.value.toLowerCase();

  allNotes.push({
    title,
    status
  });
  showDataInDOM();
});

buttons.forEach((btn) => {
  btn.addEventListener("click", (e) => {
    const type = e.target.dataset.testid;
    if (type === "allButton") {
      typeSelected = "all";
      showDataInDOM();
    } else if (type === "activeButton") {
      typeSelected = "active";
      showDataInDOM();
    } else if (type === "completedButton") {
      typeSelected = "completed";
      showDataInDOM();
    }
  });
});
.tabs {
  list-style: none;
  display: flex;
  margin: 0;
  padding: 0;
}

.tabs .tab-item {
  min-width: 88px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  position: relative;
  cursor: pointer;
  padding: 20px 16px;
  color: var(--heading-color);
}

.tabs .tab-item::before {
  content: '';
  position: absolute;
  top: 0;
  width: 100%;
  height: 2px;
  background: var(--primary-color);
  opacity: 0;
  transition: opacity 0.3s ease-in-out;
}

.tabs .tab-item:active {
  background: #fff;
  position: relative;
  color: black;
}

.tabs .tab-item:active::before {
  opacity: 1;
}

table tbody tr td {
  font-weight: bold;
  font-size: 16px;
  height: 21px;
  padding: 1.6rem;
}
<div id="root">
  <h8k-navbar header="Notes"></h8k-navbar>
  <div class="layout-column align-items-center justify-content-start">
    <section class="layout-row align-items-center justify-content-center mt-30">
      <input data-testid="input-note-name" type="text" class="large mx-8" placeholder="Note Title" />
      <input data-testid="input-note-status" type="text" class="large mx-8" placeholder="Note Status" />
      <button class="" data-testid="submit-button">Add Note</button>
    </section>
    <div class="mt-50">
      <ul class="tabs">
        <li class="tab-item slude-up-fade-in" data-testid="allButton">
          All
        </li>
        <li class="tab-item slude-up-fade-in" data-testid="activeButton">
          Active
        </li>
        <li class="tab-item slude-up-fade-in" data-testid="completedButton">
          Completed
        </li>
      </ul>
    </div>
    <div class="card w-40 pt-30 pb-8">
      <table>
        <thead>
          <tr>
            <th>Title</th>
            <th>Status</th>
          </tr>
        </thead>
        <tbody data-testid="noteList"></tbody>
      </table>
    </div>
  </div>
</div>

【讨论】:

  • 它不起作用?我的意思是 Active 和 Completed 选项卡不显示任何内容。
  • 添加a activeb completedc completed
  • all 将显示所有没有过滤器,否则显示类别明智
  • 对不起,大小写问题。
  • 添加了const status = statusInput.value.toLowerCase(),仅对状态区分大小写
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-29
  • 1970-01-01
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
相关资源
最近更新 更多