【问题标题】:Why isn't the string.length updating?为什么 string.length 没有更新?
【发布时间】:2018-11-01 07:42:58
【问题描述】:

这是我自己编写的第一段 js 代码。我正在尝试有一个输入字段来将项目添加到列表中,然后如果您按下按钮生成代码,它将收集所有选中的项目并将文本复制到另一个 div 中。

基本上,我的问题是围绕两个变量:

const list = listUl.children;
const listCopy = listUl.querySelectorAll('span');

假设我在列表中有 4 个项目。如果我在列表中添加一个新项目,我可以看到 list.length 添加这个新项目,它从 4 变为 5。 但是 listCopy.length 不会发生这种情况,该值一直为 4。

如果lstCopy 在列表内,为什么会发生这种情况? 我怎样才能更新listCopy

这是我的代码:

const addItemInput = document.querySelector('.addItemInput');
const addItemButton = document.querySelector('.addItemButton');
const copyText = document.querySelector('.generateCode');
const listUl = document.querySelector('.list');
const list = listUl.children;
const listCopy = listUl.querySelectorAll('span');
const clonedCode = document.querySelector('.code p');

//FUNCTION: Generate value/items = Draggable, Checkbox, Remove button
const attachItemListButton = (item) => {

    //Draggable
    item.draggable = "true";
    item.classList.add("list--item");

    //Checkbox
    let checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.className = 'checkbox';
    checkbox.name = "chkboxName1";
    checkbox.value = "value";
    checkbox.id = "id";
    item.insertBefore(checkbox, item.childNodes[0] || null);

    //Remove button
    let remove = document.createElement('button');
    remove.className = 'remove';
    remove.textContent = 'x';
    item.appendChild(remove);
};
for (let i = 0; i < list.length; i += 1) {
    attachItemListButton(list[i]);
}


//Cloning code if there are checked items
copyText.addEventListener('click', () => {
  let copyTextFromList = "";
  for (let i = 0; i < listCopy.length; i += 1) {
    if (listCopy[i].parentNode.querySelector("input:checked")) {
      copyTextFromList += listCopy[i].textContent + ',';
    }
  }
  clonedCode.innerHTML = copyTextFromList;
});


//Add item from the input field to the list
addItemButton.addEventListener('click', () => {
  let li = document.createElement('li');
  let span = document.createElement('span');
  span.textContent = addItemInput.value;
  listUl.appendChild(li);
  li.appendChild(span);
  attachItemListButton(li);
  addItemInput.value = '';
});


//FUNCTION: Remove button
listUl.addEventListener('click', (event) => {
    if (event.target.tagName == 'BUTTON') {
        if (event.target.className == 'remove') {
            let li = event.target.parentNode;
            let ul = li.parentNode;
            ul.removeChild(li);
        }
    }
});
/* Google fonts */
@import url('https://fonts.googleapis.com/css?family=Heebo:300,400,700');

/* Root */
:root {
    --color-white:           #fff;
    --color-black:           #2D3142;
    --color-black-2:         #0E1116;
    --color-gray:            #CEE5F2;
    --color-gray-2:          #ACCBE1;
    --color-gray-3:          #CEE5F2;
    --color-green:           #439775;
    --color-blue:           #4686CC;
}

body {
    font-family: 'Heebo', sans-serif;
    font-weight: 400;
    font-size: 16px;
    color: black;

}
h2 {
    font-weight: 700;
    font-size: 1.5rem;
}
h3 {
    font-weight: 700;
    font-size: 1.25rem;
}

button {
    background: var(--color-blue);
    padding: 5px 10px;
    border-radius: 5px;
    color: var(--color-white);
}

[draggable] {
    -moz-user-select: none;
    -khtml-user-select: none;
    -webkit-user-select: none;
    user-select: none;
    -khtml-user-drag: element;
    -webkit-user-drag: element;
}

ul.list {
    list-style-type: none;
    padding: 0;
    max-width: 300px;
}

.list  button {
    background: var(--color-black);
}

.list--item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: auto;
    margin: 5px auto;
    padding: 5px;
    cursor: move;
    background: var(--color-gray);
    border-radius: 5px;
}

.list--item.draggingElement {
    opacity: 0.4;
}

.list--item.over {
    border-top: 3px solid var(--color-green);
}

button.remove {
    margin: auto 0 auto auto;
}

input#id {
    margin: auto 5px auto 0;
}

.button-wrapper {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    max-width: 300px;
}

.button-wrapper .addItemInput { 
    width: 63%;
    border-radius: 5px 0 0 5px;
 }
.button-wrapper .addItemButton { 
    width: 35%;
    border-radius: 0 5px 5px 0;
 }
.button-wrapper .generateCode { 
    width: 100%;
    background: var(--color-green);
    margin-top: 5px;
 }


.code p {
    background: var(--color-gray); padding: 5px;
    border: 1px solid var(--color-gray-2);
    min-height: 20px;
    font-weight: 300;
}
  <ul class="list">
    <li><span>Header</span></li>
    <li><span>Hero</span></li>
    <li><span>Intro</span></li>
    <li><span>Footer</span></li>
  </ul>

  <div class="button-wrapper">
    <input type="text" class="addItemInput" placeholder="Item description">
    <button class="addItemButton">Add item</button>
    <button class="generateCode">Generate code</button>
  </div>

  <div class="code">
    <h2>Code</h2>
    <p></p>
  </div>

【问题讨论】:

  • 这与 string 长度有什么关系?

标签: javascript string-length nodelist


【解决方案1】:

NodeList 有两种变体,实时和非实时。 querySelectorAll 返回一个静态的NodeList,它不是实时的。 .children 返回一个实时的(从技术上讲,它返回一个 HTMLCollection,但您现在可以忽略这个区别)。

要使listCopy 也可以直播,您可以使用listUl.getElementsByTagName('span')...

要按类选择元素,请使用getElementsByClassName。但是,没有办法(据我所知)使用 CSS 或 XPath(即更复杂)查询获取实时集合。

【讨论】:

  • @Bravo 我认为这个评论属于这个问题,而不是我的答案......
  • 你是对的 - 抱歉(不知道这是怎么发生的)
【解决方案2】:

问题是const listCopy = listUl.querySelectorAll('span');是从一开始就用span数组初始化的。

为了获取更新列表 const listCopy = listUl.querySelectorAll('span'); 将是 let listCopy = listUl.querySelectorAll('span'); 并在您的函数中

//Cloning code if there are checked items
copyText.addEventListener('click', () => {
  // add the following line - in this way you will select the span from the updated list
  listCopy = listUl.querySelectorAll('span');
  let copyTextFromList = "";
  for (let i = 0; i < listCopy.length; i += 1) {
    if (listCopy[i].parentNode.querySelector("input:checked")) {
      copyTextFromList += listCopy[i].textContent + ',';
    }
  }
  clonedCode.innerHTML = copyTextFromList;
});

【讨论】:

    【解决方案3】:

    如果您想使用 querySelectorAll,这可能会有所帮助。每次检查长度时,它都会重新计算并返回值。 Symbol.iterator 可帮助您操作 for...of 循环。

    const addItemInput = document.querySelector('.addItemInput');
    const addItemButton = document.querySelector('.addItemButton');
    const copyText = document.querySelector('.generateCode');
    const listUl = document.querySelector('.list');
    const list = listUl.children;
    const listCopy = {
        get length() {
            return listUl.querySelectorAll('span').length
        },
        *[Symbol.iterator]() {
            let i = 0;
            const l = listUl.querySelectorAll('span');
            while( i < l.length ) {
                yield l[i];
                i++;
            }
        }
    };
    const clonedCode = document.querySelector('.code p');
    
    //FUNCTION: Generate value/items = Draggable, Checkbox, Remove button
    const attachItemListButton = (item) => {
    
        //Draggable
        item.draggable = "true";
        item.classList.add("list--item");
    
        //Checkbox
        let checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.className = 'checkbox';
        checkbox.name = "chkboxName1";
        checkbox.value = "value";
        checkbox.id = "id";
        item.insertBefore(checkbox, item.childNodes[0] || null);
    
        //Remove button
        let remove = document.createElement('button');
        remove.className = 'remove';
        remove.textContent = 'x';
        item.appendChild(remove);
    };
    for (let i = 0; i < list.length; i += 1) {
        attachItemListButton(list[i]);
    }
    
    
    //Cloning code if there are checked items
    copyText.addEventListener('click', () => {
      let copyTextFromList = "";
      for (let item of listCopy) {
        if (item.parentNode.querySelector("input:checked")) {
          copyTextFromList += item.textContent + ',';
        }
      }
      clonedCode.innerHTML = copyTextFromList;
    });
    
    
    //Add item from the input field to the list
    addItemButton.addEventListener('click', () => {
      let li = document.createElement('li');
      let span = document.createElement('span');
      span.textContent = addItemInput.value;
      listUl.appendChild(li);
      li.appendChild(span);
      attachItemListButton(li);
      addItemInput.value = '';
    });
    
    
    //FUNCTION: Remove button
    listUl.addEventListener('click', (event) => {
        if (event.target.tagName == 'BUTTON') {
            if (event.target.className == 'remove') {
                let li = event.target.parentNode;
                let ul = li.parentNode;
                ul.removeChild(li);
            }
        }
    });
    /* Google fonts */
    @import url('https://fonts.googleapis.com/css?family=Heebo:300,400,700');
    
    /* Root */
    :root {
        --color-white:           #fff;
        --color-black:           #2D3142;
        --color-black-2:         #0E1116;
        --color-gray:            #CEE5F2;
        --color-gray-2:          #ACCBE1;
        --color-gray-3:          #CEE5F2;
        --color-green:           #439775;
        --color-blue:           #4686CC;
    }
    
    body {
        font-family: 'Heebo', sans-serif;
        font-weight: 400;
        font-size: 16px;
        color: black;
    
    }
    h2 {
        font-weight: 700;
        font-size: 1.5rem;
    }
    h3 {
        font-weight: 700;
        font-size: 1.25rem;
    }
    
    button {
        background: var(--color-blue);
        padding: 5px 10px;
        border-radius: 5px;
        color: var(--color-white);
    }
    
    [draggable] {
        -moz-user-select: none;
        -khtml-user-select: none;
        -webkit-user-select: none;
        user-select: none;
        -khtml-user-drag: element;
        -webkit-user-drag: element;
    }
    
    ul.list {
        list-style-type: none;
        padding: 0;
        max-width: 300px;
    }
    
    .list  button {
        background: var(--color-black);
    }
    
    .list--item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        width: auto;
        margin: 5px auto;
        padding: 5px;
        cursor: move;
        background: var(--color-gray);
        border-radius: 5px;
    }
    
    .list--item.draggingElement {
        opacity: 0.4;
    }
    
    .list--item.over {
        border-top: 3px solid var(--color-green);
    }
    
    button.remove {
        margin: auto 0 auto auto;
    }
    
    input#id {
        margin: auto 5px auto 0;
    }
    
    .button-wrapper {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
        max-width: 300px;
    }
    
    .button-wrapper .addItemInput { 
        width: 63%;
        border-radius: 5px 0 0 5px;
     }
    .button-wrapper .addItemButton { 
        width: 35%;
        border-radius: 0 5px 5px 0;
     }
    .button-wrapper .generateCode { 
        width: 100%;
        background: var(--color-green);
        margin-top: 5px;
     }
    
    
    .code p {
        background: var(--color-gray); padding: 5px;
        border: 1px solid var(--color-gray-2);
        min-height: 20px;
        font-weight: 300;
    }
      <ul class="list">
        <li><span>Header</span></li>
        <li><span>Hero</span></li>
        <li><span>Intro</span></li>
        <li><span>Footer</span></li>
      </ul>
    
      <div class="button-wrapper">
        <input type="text" class="addItemInput" placeholder="Item description">
        <button class="addItemButton">Add item</button>
        <button class="generateCode">Generate code</button>
      </div>
    
      <div class="code">
        <h2>Code</h2>
        <p></p>
      </div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-12
      • 2021-08-04
      • 2020-04-18
      • 1970-01-01
      相关资源
      最近更新 更多