如何将onclick事件侦听器添加到桌子上?

发布于 2025-01-21 14:12:20 字数 648 浏览 0 评论 0 原文

我目前正在尝试添加一个功能,当我在表中单击用户的名称时,它将显示该用户发表的所有帖子,但是我完全陷入困境。帖子的URL为 https://jsonplaceholder.typicode.com/posts

我目前有桌子设置并将连接下面的表格和代码的图像。

这是我试图

使用 jquery js js js js y y https://jquery.com/“ https://jquery.com/”将在表中显示每个用户。当用户在表中选择用户时,它将显示由该用户创建的所有“帖子”。

“

​“ data.json”>

I am currently trying to add a feature where when I click the name of a user in the table it will display all of the posts made by that User however I am completely stumped. The url for the posts is https://jsonplaceholder.typicode.com/posts

I currently have the table set up and will attach images of the table and code below.

Here is the problem I am trying to solve for further context

Using jQuery or vanilla JS you will display each USER in a table. When the user selects a USER in the table, it will display all of the 'POSTS' that were created by that USER.

index.js

index.html

table

data.json

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

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

发布评论

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

评论(1

oО清风挽发oО 2025-01-28 14:12:20

利用 代码> 分别属性 htmlelement.dataset 对应物。

document
  .querySelector('tbody')
  .addEventListener('click', ({ target }) => {

    const currentRow = target.closest('tr');
    const userId = currentRow.dataset.id;

    console.clear();
    console.log('userId: ', userId);
  });
body {
  margin: 0 0 0 2px;
}
table {
  border-collapse: collapse;
}
thead th {
  color: #fff;
  font-weight: bolder;
  background-color: #009577;
}
th, td {
  padding: 4px 10px 6px 10px;
  color: #0a0a0a;
}
tbody tr:nth-child(even) {
  background-color: #eee;
}
tbody tr:hover {
  outline: 2px dotted orange;
}
tbody tr {
  cursor: pointer;
}



tbody tr:nth-child(even) { background-color: #eee; }
tbody tr:hover { outline: 2px dotted orange; }
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Name</th>
      <th>Username</th>
      <th>Email</th>
    </tr>
  </thead>
  <tbody>
    <tr data-id='1'>
      <td>1</td>
      <td>Leanne Graham</td>
      <td>Bret</td>
      <td>[email protected]</td>
    </tr>
    <tr data-id='2'>
      <td>2</td>
      <td>Ervin Howell</td>
      <td>Antonette</td>
      <td>[email protected]</td>
    </tr>
    <tr data-id='3'>
      <td>3</td>
      <td>Clementine Bauch</td>
      <td>Samantha</td>
      <td>[email protected]</td>
    </tr>
    <tr data-id='4'>
      <td>4</td>
      <td>Patricia Lebsack</td>
      <td>Karianne</td>
      <td>[email protected]</td>
    </tr>
    <tr data-id='5'>
      <td>5</td>
      <td>Chelsey Dietrich</td>
      <td>Kamren</td>
      <td>[email protected]</td>
    </tr>
  </tbody>
</table>

基于香草的类似于组件的方法的实现,该方法可通过 数据 - * 属性可能看起来像下一个提供的示例代码...

function emptyElementNode(node) {
  [...node.childNodes].forEach(child => child.remove());
}
function clearTableContent(root) {
  [
    ...root.querySelectorAll('thead'), 
    ...root.querySelectorAll('tbody'),

  ].forEach(child => child.remove());
}

function createTableHead(headerContentList) {
  const elmThead = document.createElement('thead');
  const elmTr = headerContentList
    .reduce((root, content) => {

      const elmTh = document.createElement('th');
      elmTh.textContent = content;

      root.appendChild(elmTh);

      return root;      
    }, document.createElement('tr'));
  
  elmThead.appendChild(elmTr);
  return elmThead;
}
function createTableBody(rowContentKeyList, userList) {
  return userList
    .reduce((elmTbody, userItem) => {

      const elmTr = rowContentKeyList
        .reduce((root, key) => {

          const elmTd = document.createElement('td');
          elmTd.textContent = userItem[key];

          root.appendChild(elmTd);

          return root;
        }, document.createElement('tr'));

      elmTr.dataset.id = userItem.id;
      elmTbody.appendChild(elmTr);

      return elmTbody;
    }, document.createElement('tbody'));
}
function createAndRenderPostItem(root, { title, body }) {
  const elmDt = document.createElement('dt');
  const elmDd = document.createElement('dd');

  elmDt.textContent = title;
  elmDd.textContent = body;

  root.appendChild(elmDt);
  root.appendChild(elmDd);

  return root;
}

function updateSelectedStates(selectedRow) {
  [...selectedRow.parentNode.children]
    .forEach(rowNode =>
      rowNode.classList.remove('selected')
    );
  selectedRow.classList.add('selected');
}

function handleUserPostsRequestFromBoundData({ target }) {
  const { postsRoot, requestUrl, placeholder } = this;

  const currentRow = target.closest('tr');
  const userId = currentRow?.dataset?.id;

  if (userId) {
    createListOfUserPosts({
      postsRoot,
      url: requestUrl.replace(placeholder, userId)
    });
    updateSelectedStates(currentRow);
  }
}

async function createListOfUserPosts({ postsRoot, url }) {
  emptyElementNode(postsRoot);

  if (postsRoot && url) {
    const response = await fetch(url);
    const postList = await response.json();

    postList.reduce(createAndRenderPostItem, postsRoot);
  }
}
async function createListOfUsers({ usersRoot, postsRoot }) {
  const usersRequestUrl = usersRoot.dataset.request;

  const userPostsRequestUrl = postsRoot.dataset.request;
  const userPostsPlaceholder = postsRoot.dataset.placeholder;

  const response = await fetch(usersRequestUrl);
  const userList = await response.json();

  if (userList.length >= 1) {
    const displayConfig = JSON.parse(
      usersRoot.dataset.display ?? '{}'
    );
    const headerContentList = Object.values(displayConfig);
    const rowContentKeyList = Object.keys(displayConfig);

    emptyElementNode(postsRoot);
    clearTableContent(usersRoot);

    usersRoot.appendChild(
      createTableHead(headerContentList)
    );
    usersRoot.appendChild(
      createTableBody(rowContentKeyList, userList)
    );
    usersRoot.addEventListener(
      'click',
      handleUserPostsRequestFromBoundData
        .bind({
          postsRoot,
          requestUrl: userPostsRequestUrl,
          placeholder: userPostsPlaceholder,
        })
    );
  }  
}

function initializeUserPostsComponent(root) {
  const usersRoot = root.querySelector('[data-users]');
  const postsRoot = root.querySelector('[data-posts]');

  createListOfUsers({ usersRoot, postsRoot });
}
document
  .querySelectorAll('[data-user-posts]')
  .forEach(initializeUserPostsComponent);
body { margin: 0 0 0 2px; font-size: .8em; }
table { border-collapse: collapse; }
table caption { text-align: left; padding: 3px; }
thead th { color: #fff; font-weight: bolder; background-color: #009577; }
th, td { padding: 3px 5px; color: #0a0a0a; }
tbody tr:nth-child(even) { background-color: #eee; }
tbody tr:hover { outline: 2px dotted orange; }
tbody tr.selected { background-color: rgb(255 204 0 / 18%); }
tbody tr { cursor: pointer; }
[data-user-posts]::after { clear: both; display: inline-block; content: ''; }
.user-overview { float: left; width: 63%; }
.user-posts { float: right; width: 36%; }
.user-posts h3 { margin: 0; padding: 4px 8px; font-size: inherit; font-weight: normal; }
<article data-user-posts>
  <table 
    data-users
    data-request="https://jsonplaceholder.typicode.com/users"
    data-display='{"id":"Id","name":"Name","username":"Username","email":"Email"}'
    class="user-overview"
  >
    <caption>Select a user to view posts</caption>
  </table>
  <div class="user-posts">
    <h3>Posts:</h3>
    <dl
      data-posts
      data-request="https://jsonplaceholder.typicode.com/users/:userId/posts"
      data-placeholder=":userId"
    >
    </dl>
  </div>
<article>

Make use of event delegation together with Element.closest and the data-* attribute respectively its HTMLElement.dataset counterpart.

document
  .querySelector('tbody')
  .addEventListener('click', ({ target }) => {

    const currentRow = target.closest('tr');
    const userId = currentRow.dataset.id;

    console.clear();
    console.log('userId: ', userId);
  });
body {
  margin: 0 0 0 2px;
}
table {
  border-collapse: collapse;
}
thead th {
  color: #fff;
  font-weight: bolder;
  background-color: #009577;
}
th, td {
  padding: 4px 10px 6px 10px;
  color: #0a0a0a;
}
tbody tr:nth-child(even) {
  background-color: #eee;
}
tbody tr:hover {
  outline: 2px dotted orange;
}
tbody tr {
  cursor: pointer;
}



tbody tr:nth-child(even) { background-color: #eee; }
tbody tr:hover { outline: 2px dotted orange; }
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Name</th>
      <th>Username</th>
      <th>Email</th>
    </tr>
  </thead>
  <tbody>
    <tr data-id='1'>
      <td>1</td>
      <td>Leanne Graham</td>
      <td>Bret</td>
      <td>[email protected]</td>
    </tr>
    <tr data-id='2'>
      <td>2</td>
      <td>Ervin Howell</td>
      <td>Antonette</td>
      <td>[email protected]</td>
    </tr>
    <tr data-id='3'>
      <td>3</td>
      <td>Clementine Bauch</td>
      <td>Samantha</td>
      <td>[email protected]</td>
    </tr>
    <tr data-id='4'>
      <td>4</td>
      <td>Patricia Lebsack</td>
      <td>Karianne</td>
      <td>[email protected]</td>
    </tr>
    <tr data-id='5'>
      <td>5</td>
      <td>Chelsey Dietrich</td>
      <td>Kamren</td>
      <td>[email protected]</td>
    </tr>
  </tbody>
</table>

A vanilla based implementation of a component-like approach which is partially configurable via data-* attributes then possibly might look like the next provided example code ...

function emptyElementNode(node) {
  [...node.childNodes].forEach(child => child.remove());
}
function clearTableContent(root) {
  [
    ...root.querySelectorAll('thead'), 
    ...root.querySelectorAll('tbody'),

  ].forEach(child => child.remove());
}

function createTableHead(headerContentList) {
  const elmThead = document.createElement('thead');
  const elmTr = headerContentList
    .reduce((root, content) => {

      const elmTh = document.createElement('th');
      elmTh.textContent = content;

      root.appendChild(elmTh);

      return root;      
    }, document.createElement('tr'));
  
  elmThead.appendChild(elmTr);
  return elmThead;
}
function createTableBody(rowContentKeyList, userList) {
  return userList
    .reduce((elmTbody, userItem) => {

      const elmTr = rowContentKeyList
        .reduce((root, key) => {

          const elmTd = document.createElement('td');
          elmTd.textContent = userItem[key];

          root.appendChild(elmTd);

          return root;
        }, document.createElement('tr'));

      elmTr.dataset.id = userItem.id;
      elmTbody.appendChild(elmTr);

      return elmTbody;
    }, document.createElement('tbody'));
}
function createAndRenderPostItem(root, { title, body }) {
  const elmDt = document.createElement('dt');
  const elmDd = document.createElement('dd');

  elmDt.textContent = title;
  elmDd.textContent = body;

  root.appendChild(elmDt);
  root.appendChild(elmDd);

  return root;
}

function updateSelectedStates(selectedRow) {
  [...selectedRow.parentNode.children]
    .forEach(rowNode =>
      rowNode.classList.remove('selected')
    );
  selectedRow.classList.add('selected');
}

function handleUserPostsRequestFromBoundData({ target }) {
  const { postsRoot, requestUrl, placeholder } = this;

  const currentRow = target.closest('tr');
  const userId = currentRow?.dataset?.id;

  if (userId) {
    createListOfUserPosts({
      postsRoot,
      url: requestUrl.replace(placeholder, userId)
    });
    updateSelectedStates(currentRow);
  }
}

async function createListOfUserPosts({ postsRoot, url }) {
  emptyElementNode(postsRoot);

  if (postsRoot && url) {
    const response = await fetch(url);
    const postList = await response.json();

    postList.reduce(createAndRenderPostItem, postsRoot);
  }
}
async function createListOfUsers({ usersRoot, postsRoot }) {
  const usersRequestUrl = usersRoot.dataset.request;

  const userPostsRequestUrl = postsRoot.dataset.request;
  const userPostsPlaceholder = postsRoot.dataset.placeholder;

  const response = await fetch(usersRequestUrl);
  const userList = await response.json();

  if (userList.length >= 1) {
    const displayConfig = JSON.parse(
      usersRoot.dataset.display ?? '{}'
    );
    const headerContentList = Object.values(displayConfig);
    const rowContentKeyList = Object.keys(displayConfig);

    emptyElementNode(postsRoot);
    clearTableContent(usersRoot);

    usersRoot.appendChild(
      createTableHead(headerContentList)
    );
    usersRoot.appendChild(
      createTableBody(rowContentKeyList, userList)
    );
    usersRoot.addEventListener(
      'click',
      handleUserPostsRequestFromBoundData
        .bind({
          postsRoot,
          requestUrl: userPostsRequestUrl,
          placeholder: userPostsPlaceholder,
        })
    );
  }  
}

function initializeUserPostsComponent(root) {
  const usersRoot = root.querySelector('[data-users]');
  const postsRoot = root.querySelector('[data-posts]');

  createListOfUsers({ usersRoot, postsRoot });
}
document
  .querySelectorAll('[data-user-posts]')
  .forEach(initializeUserPostsComponent);
body { margin: 0 0 0 2px; font-size: .8em; }
table { border-collapse: collapse; }
table caption { text-align: left; padding: 3px; }
thead th { color: #fff; font-weight: bolder; background-color: #009577; }
th, td { padding: 3px 5px; color: #0a0a0a; }
tbody tr:nth-child(even) { background-color: #eee; }
tbody tr:hover { outline: 2px dotted orange; }
tbody tr.selected { background-color: rgb(255 204 0 / 18%); }
tbody tr { cursor: pointer; }
[data-user-posts]::after { clear: both; display: inline-block; content: ''; }
.user-overview { float: left; width: 63%; }
.user-posts { float: right; width: 36%; }
.user-posts h3 { margin: 0; padding: 4px 8px; font-size: inherit; font-weight: normal; }
<article data-user-posts>
  <table 
    data-users
    data-request="https://jsonplaceholder.typicode.com/users"
    data-display='{"id":"Id","name":"Name","username":"Username","email":"Email"}'
    class="user-overview"
  >
    <caption>Select a user to view posts</caption>
  </table>
  <div class="user-posts">
    <h3>Posts:</h3>
    <dl
      data-posts
      data-request="https://jsonplaceholder.typicode.com/users/:userId/posts"
      data-placeholder=":userId"
    >
    </dl>
  </div>
<article>

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