javascript - 使用 JavaScript DOM 使用对象数组重写数据属性数组

标签 javascript html arrays dom

我是 JavaScript 新手。我想要做的是重写我的 data-project 属性以显示我的 projects 数组中的内容,如果 projects 数组大于 6,因为项目框只能容纳 6 个。我一直在尝试查找有关 DOM 的更多信息,但我没有找到适合我的情况的信息。 如果需要更多代码来帮助您理解,请告诉我。还有一些按钮可以过滤存储在数组(位于不同文件中)中的内容。此文件也导入到我的 index.html 中。

此外,如果您有任何学习 DOM 的重要资源,我很乐意将它们发送给我。谢谢!

我的 HTML

<div class="wrapper">
          <div class="row" data-project="1">
          <img class="logo" src="https://static.vecteezy.com/system/resources/previews/000/350/423/non_2x/vector-checklist-icon.jpg" alt="image">
          <div class="top">
            <h3 class="title">Job Listing</h3>
            <h6 class="language">HTML/CSS</h6>
            <p class="desc">Static Page Containing Job Listings</p>
            </div>

          <div class="bottom">
            <div class="image"> </div>
            <p class="type">Personal</p>
            </div>
            </div>

            <div class="row" data-project="2">
          <img class="logo" src="https://static.vecteezy.com/system/resources/previews/000/350/423/non_2x/vector-checklist-icon.jpg" alt="image">
          <div class="top">
            <h3 class="title">Calculator</h3>
            <h6 class="language">HTML/CSS, JavaScript</h6>
            <p class="desc">Basic JavaScript Calculator</p>
            </div>

          <div class="bottom">
            <div class="image"> </div>
            <p class="type">Personal</p>
            </div>
            </div>
            <div class="row" data-project="3">
          <img class="logo" src="https://static.vecteezy.com/system/resources/previews/000/350/423/non_2x/vector-checklist-icon.jpg" alt="image">
          <div class="top">
            <h3 class="title">TODO</h3>
            <h6 class="language">HTML/CSS, JavaScript, React</h6>
            <p class="desc">Organize your everyday life with this web app made with React</p>
            </div>

          <div class="bottom">
            <div class="image"> </div>
            <p class="type">Personal</p>
            </div>
            </div>
            <div class="row" data-project="4">
          <img class="logo" src="https://static.vecteezy.com/system/resources/previews/000/350/423/non_2x/vector-checklist-icon.jpg" alt="image">
          <div class="top">
            <h3 class="title">Login and Signup</h3>
            <h6 class="language">HTML/CSS</h6>
            <p class="desc">Static Page for logging in and signing up</p>
            </div>

          <div class="bottom">
            <div class="image"> </div>
            <p class="type">Personal</p>
            </div>
            </div>

              <div class="row" data-project="5">
          <img class="logo" src="https://static.vecteezy.com/system/resources/previews/000/350/423/non_2x/vector-checklist-icon.jpg" alt="image">
          <div class="top">
            <h3 class="title">RNG Therapy Site</h3>
            <h6 class="language">WordPress</h6>
            <p class="desc">WordPress site that allows users to schedule appointments.</p>
            </div>

          <div class="bottom">
            <div class="image"> </div>
            <p class="type">Client</p>
            </div>
            </div>

              <div class="row" data-project="6">
          <img class="logo" src="https://static.vecteezy.com/system/resources/previews/000/350/423/non_2x/vector-checklist-icon.jpg" alt="image">
          <div class="top">
            <h3 class="title">Coffee Shop Website</h3>
            <h6 class="language">HTML/CSS, JavaScript, React</h6>
            <p class="desc">Static Page for a Coffee Shop</p>
            </div>

          <div class="bottom">
            <div class="image"> </div>
            <p class="type">Client</p>
            </div>
            </div>
</div>

我的 JavaScript(我知道它很乱)

const projectAttributes = [
    document.querySelector('[data-project="1"]'),
    document.querySelector('[data-project="2"]'),
    document.querySelector('[data-project="3"]'),
    document.querySelector('[data-project="4"]'),
    document.querySelector('[data-project="5"]'),
    document.querySelector('[data-project="6"]'),
];

let i = 0;

function domReplaceProjects(projects) {
    console.log(projectAttributes.length);
    //Use projects array size for loop conditional
    if(projects.length <= 6) {
        for(i = 0; i <= projects.length; i++) {
            projectAttributes[i] = `
                  <div class="top">
                    <h3 class="title">${project.name}</h3>
                    <h6 class="language">${project.desc}</h6>
                    <p class="desc">${project.language}</p>
                </div>

                <div class="bottom">
                    <div class="image"> </div>
                    <p class="type">${project.type}</p>
                </div>

                    <div class="row">
                    <img class="logo" src="https://static.vecteezy.com/system/resources/previews/000/350/423/non_2x/vector-checklist-icon.jpg" alt="image">
                 </div>
                `
        }
    }
    //Use data attributes array size for loop conditional
    else {
        for(i = 0; i < projectAttributes.length; i++) {
            //logic here
        }
    }
}

最佳答案

动态添加元素——有两种方式。

向 DOM 添加元素的两种最常见的方法是:

  1. 创建 htmlString元素的一部分,并通过...将其呈现给父元素

  2. 通过 document.createElement() 创建一个元素并将其添加到目标元素作为最后一个子元素 .appendChild() .

问题

选项 #1 似乎是 OP 代码打算实现的。虽然有一个 htmlStringprojectAttributes 的每次迭代声明,没有呈现 htmlString 的明显属性、方法或函数作为真正的 HTML 到 DOM。此外,projectAttributes数组已经声明(顺便说一句,有更好的方法将元素收集到 NodeList 或数组 -- document.querySelectorAll('.row') 中)。

此外,大约有 6 个单独的对象实例及其键/值,但在每次迭代中表示时,当前对象未正确指示。通过property效率不是很高作为一个对象(例如 {key1: value, key2: value,...} ),因为似乎没有办法处理多个对象。

演示

下面的演示有一个函数将接受一个对象数组(例如 [{a: 1, b: "c"}, {a: 2, b: "d"},...] ,一个确定迭代限制的数字,以及一个可选的 bool 值,它确定 DOM 的现有 HTML 是否被新的覆盖HTML 或新的 HTML 被插入到 DOM 中,从而保留了现有的 HTML。还有一个 float 的 <form> 将演示三个用法示例(该部分源代码对于答案的解决方案不是必需的,它是在代码中明确注明)。更多详细信息在演示中进行了评论。

let projects = [{
    title: "Convertor",
    tech: "HTML/CSS/JavaScript",
    desc: "Calculates and converts measurements",
    url: "/projects/convertor.html",
    pro: false
  },
  {
    title: "RNG Therapy",
    tech: "WordPress Platform",
    desc: "Schedules appointments for clients",
    url: "https://app.rngt.com",
    pro: true
  },
  {
    title: "TODO List",
    tech: "HTML/CSS/JavaScript",
    desc: "Editable task list with autosave",
    url: "/projects/todo_list.html",
    pro: false
  },
  {
    title: "Kelly's Krafts",
    tech: "Etsy Platform",
    desc: "Custom shopping cart",
    url: "https://etsy.com/shop/KellysKrafts",
    pro: true
  },
  {
    title: "TEST 5",
    tech: "HTML/CSS/jQuery",
    desc: "Test client object (professional list)",
    url: "https://example.com",
    pro: true
  },
  {
    title: "TEST 6",
    tech: "HTML/CSS",
    desc: "Test demo object (personal list)",
    url: "/projects/test.html",
    pro: false
  },
  {
    title: "TEST 7",
    tech: "HTML/CSS/JavaScript",
    desc: "Test limit object (professional list) - if limit is set to 6, this should not be rendered",
    pro: true
  }
];

let TEST = [{
    title: "TEST 8",
    tech: "React Framework",
    desc: "Test demo object (personal list)",
    pro: false
  },
  {
    title: "TEST 9",
    tech: undefined,
    desc: "Test client object (professional list)",
    pro: true
  },
  {
    title: "TEST A",
    tech: "JavaScript (ES6)",
    desc: "Test client object (professional list)",
    pro: true
  },
  {
    title: "TEST B",
    tech: "HTML/CSS(LESS)",
    desc: "Test demo object (personal list)",
    pro: false
  }
];


/*
 ** setLists(array, limit, overwrite)
 ** @Params
 **  - array [Array]: An array of objects. 
 **    Each object should have the following keys:
 **    title, tech, desc, and pro 
 **  - limit [Number]: How many objects get processed.
 **  - overwrite [Boolean] {optional}: If undefined it is `true` by default.
 **    true: All content of each list will be removed before the new content is added.
 **    false: New content will be added after the old content.
 ** Purpose: Render <li> with content determined by a given array of objects.
 */
const setLists = (array, limit, overwrite = true) => {

  // Collect all <ul> into a NodeList
  const lists = document.querySelectorAll('ul');

  /* If {limit} is greater than the number of objects in {array} OR (ie ||)
  if {limit} is less then 1 OR (ie ||) {limit} isn't a number at all...
  then {limit} will be equal to the number of objects within {array}
  */
  if (limit > array.length || limit < 1 || Number.isNaN(limit)) {
    limit = array.length;
  }

  /* If {overwrite} is true (this is default)...
  then remove all content of each <ul>
  */
  if (overwrite) {
    for (let list of lists) {
      let range = document.createRange();
      range.selectNodeContents(list);
      range.deleteContents();
    }
  }

  // Each <ul>...
  for (let i = 0; i < limit; i++) {

    /* Declare {item} as a htmlString
    Note:
    - Each array element is an object (ex. array[i])     
    - The current position of the object is indicated by an index number (ex. array[i] "i" is index)
    - The property (or key) name is suffixed (ex. array[i].key)
    - The result is the value: 
      (ex. <h3>${array[2].title}</h3> is <h3>TODO List</h3>)
    */
    let item = `
      <li>
        <header>
          <h3><a href='${array[i].url}'>${array[i].title}</a></h3>
          <p>${array[i].tech}</p>
        </header>
        <article>${array[i].desc}</article>
      </li>`;

    // If the current object key "pro" is true...
    if (array[i].pro) {

      // Insert and render the htmlString as HTML as the last <li> of the first <ul>...
      lists[0].insertAdjacentHTML('beforeend', item);

      // otherwise...
    } else {

      // do it to the second <ul>
      lists[1].insertAdjacentHTML('beforeend', item);
    }
  }
  // Terminate function
  return false;
}

/*~~~The JS below is for demo purposes only~~~*/

document.querySelector('legend, summary').onclick = function(e) {
  document.querySelector('main').classList.toggle('shift-down');
}


const ui = document.forms[0];

ui.onchange = runExamples;

function runExamples(e) {
  const examples = [{
      fnc: 'setLists(projects, null)',
      act: 'Passing an array of objects and null'
    },
    {
      fnc: 'setLists(projects, 3)',
      act: 'Passing array of only the first 3 objects and overwritting previous lists'
    },
    {
      fnc: 'setLists(TEST, null, false)',
      act: 'Passing a different array of objects and appending it to the lists'
    }
  ];

  const fields = ui.elements;
  const exampleBtn = fields.exp;
  const messageOut = fields.msg;

  if (e.target.name === 'exp') {
    let index = Number(e.target.dataset.idx);
    switch (index) {
      case 0:
        setLists(projects, null);
        break;
      case 1:
        setLists(projects, 3);
        break;
      case 2:
        setLists(TEST, null, false);
        break;
      default:
        break;
    }
    messageOut[0].value = examples[index].fnc;
    messageOut[1].value = examples[index].act;

    for (let button of exampleBtn) {
      button.parentElement.classList.remove('active');
    }
    e.target.parentElement.classList.add('active');
  }
  return false;
}
/*~~~The JS above is not required~~~*/
:root {
  font: 16px/1 Arial
}

html,
body {
  width: 100%;
  height: 100%;
}


/*~~~The CSS below is for demo purposes only~~~*/

form {
  position: relative;
}

details {
  position: fixed;
  top: 5vh;
  right: 10vw;
  z-index: 1;
  width: 50vw;
}

details[open] summary {
  position: absolute;
}

fieldset {
  font-size: 0.8rem;
  padding: 5px 5px 5px 8px;
  background: #fff;
}

summary,
legend {
  color: #930;
  font-size: 1rem;
  cursor: pointer;
  border: 1px solid grey;
  border-radius: 4px;
  padding: 3px 5px;
  background: #fff;
}

.btn {
  display: inline-block;
  width: max-content;
  padding: 3px 5px;
  margin: 5px -3px;
  cursor: pointer;
  border: 1px solid grey;
}

.btn.active {
  color: blue;
}

.btn:hover {
  color: green;
}

.left {
  border-top-left-radius: 5px;
  border-bottom-left-radius: 5px;
  margin-left: 8px;
}

.right {
  border-top-right-radius: 5px;
  border-bottom-right-radius: 5px;
  margin-right: 8px;
}

output {
  display: block;
  height: 3ex;
  width: 90%;
  margin: 5px;
  padding: 6px 3px 3px;
}

output:first-of-type {
  color: lime;
  background: #333;
  font-family: 'Lucida Console';
  font-weight: 700;
  padding-bottom: 0;
}

output:last-of-type {
  margin-top: 0
}


/*The CSS above is not required*/

main {
  display: flex;
  flex-flow: column nowrap;
  width: 70vw;
  height: max-content;
  padding: 5vh 20vw 10vh 10vw
}

main.shift-down {
  padding-top: 50vh;
}

h1 {
  font-size: 1.55rem;
  margin-bottom: 5px
}

h2 {
  font-size: 1.45rem;
  margin-bottom: 5px
}

h3 {
  font-size: 1.25rem;
  margin-bottom: 5px
}

header {
  margin-bottom: 5px
}

header p {
  font-style: italic;
  margin: 0;
}

h1+p {
  font-size: 1.4rem
}

h2+p {
  font-size: 1.3rem
}

h3+p {
  font-size: 1.1rem
}

.row {
  display: flex;
  flex-flow: row nowrap;
  width: 100%;
  height: max-content;
}

.logo {
  max-height: 120px;
  padding: 0;
  margin-left: -10px;
  margin-right: 5px
}

.logo img {
  display: block;
  max-width: 75px;
  height: auto;
}

.line {
  margin-top: -5px;
}

ul {
  list-style: none;
  padding-left: 5vw;
  margin-top: 5px
}

a {
  text-decoration: none;
  color: #930;
}

a:hover {
  text-decoration: underline
}
<!DOCTYPE html>
<html lang='en'>

<head>
  <title>Web Portfolio</title>
  <meta charset='utf-8'>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!--<link href='/projects/externalStyleFile.css' ref='stylesheet'>-->
  <style>
    /*CSS goes here (see <link> above for external CSS)*/
  </style>
</head>

<body>

  <!--The HTML below is for demo purposes only-->
  <form>
    <details>
      <summary>Examples</summary>
      <fieldset>
        <legend>Examples</legend>
        <label class='btn left'><input name='exp' data-idx='0' type='radio' hidden>Example 1</label>
        <label class='btn'><input name='exp' data-idx='1'type='radio' hidden>Example 2</label>
        <label class='btn right'><input name='exp' data-idx='2' type='radio' hidden>Example 3</label><br>
        <label>Function: </label><br>
        <output name='msg'></output>
        <label>Action: </label><br>
        <output name='msg'></output>
      </fieldset>
    </details>
  </form>
  <!--The HTML above is not required-->

  <main>
    <header class='row'>
      <figure class='logo'>
        <img src="https://static.vecteezy.com/system/resources/previews/000/350/423/non_2x/vector-checklist-icon.jpg" alt="icon of a checklist">
      </figure>
      <hgroup>
        <h1>Web Portfolio</h1>
        <p>Web development projects</p>
      </hgroup>
    </header>
    <div class='line'>
      <hr>
    </div>
    <header>
      <h2>Profesional</h2>
      <p>List of client projects</p>
    </header>
    <ul></ul>

    <header>
      <h2>Personal</h2>
      <p>List of project demos</p>
    </header>
    <ul></ul>

  </main>
  <!--<script src='/projects/externalScriptFile.js'></script>-->
  <script>
    /*JavaScript goes here (see <script> above for external JS)*/
  </script>
</body>

</html>

关于javascript - 使用 JavaScript DOM 使用对象数组重写数据属性数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59276857/

相关文章:

javascript - 当父组件的状态更新时,子组件的 props 不会更新

javascript - 在 Javascript 中插入文本框值未通过 ASP.NET 验证

jquery - 如何使用 Bxslider 连续显示 4 张幻灯片

Javascript 输入返回 NaN 或未定义

javascript - 按字母顺序排列 Angular 过滤器,但将新添加到顶部

javascript - 在弹出窗口中显示来自 GeoJson 的信息 (LEAFLET)

php - 重定向回 Laravel 中的相同位置

javascript - 比较数组变量

ios - 类型 '_' 的值没有成员

SQL遍历数组