JavaScript函数出错导致不必要的递归行为

问题描述 投票:0回答:2

我有一个隐藏的表单,其中包含一些文本字段和一个触发submit()的按钮。

let library = [];
const addToLibButton = document.getElementById('addToLib');

addToLibButton.addEventListener('click', addBookToLibrary);

function Book(title, author, numPages, read){
    this.title = title,
    this.author = author,
    this.numPages = numPages,
    this.read = read;
}

Book.prototype.info = function(){
    return [this.title, this.author, this.numPages, this.read]
}

function emptyException(message){
    this.message = message;
    this.name = 'emptyException';
}

emptyException.prototype.toString = function() {
    return this.name + ': "' + this.message + '" ';
}

function addBookToLibrary(){
    let form = document.getElementById('form');

    const submitButton = document.getElementById('submit');
    submitButton.addEventListener('click', submit)

    alert('Please enter information about the book into the form.');
    form.hidden = false;

    function clearLibraryContainer(){
        let libElement = document.getElementById('library');
        if(libElement.hasChildNodes()){
            libElement.childNodes.forEach(function(childNode){
                childNode.remove();
            });
        }

        return;
    }

    function submit() {
        let title = document.getElementById('title'),
            author = document.getElementById('author'),
            numPages = document.getElementById('numPages'),            
            readOrNot = document.getElementsByName('readAnswer');
        
        try {
            if(title.value == '' || author.value == '' || numPages == ''){
                throw new emptyException('You cannot leave any fields blank.');
            }
        }
        catch(err){
            alert(err.message);
            return;
        }

        readOrNot.forEach(function(radioButton){
            if(radioButton.checked){
                readOrNot = radioButton.value;
            }
        });

        library.push(new Book(title.value, author.value, numPages.value, readOrNot));

        title.value = '';
        author.value = '';
        numPages.value = '';
        form.hidden = true;
        clearLibraryContainer();
        render();
        return;
    }
    return;
}

function render(){
    let libElement = document.getElementById('library');

    library.forEach(function(book, index){
        let bookCard = document.createElement('span');
        bookCard.dataset.arrayIndex = index;
        
        book.info().forEach(function(info, index){
        let text = document.createElement('p');
            switch(index){
                case 0:
                    text.innerText = info;
                    break;
                case 1:
                    text.innerText = `Written by: ${info}`;
                    break;
                case 2:
                    text.innerText = `${info} pages long.`;
                    break;
                default:
                    text.innerText = `Status: ${info}`;
                    break;
            }
            bookCard.appendChild(text);
        });

        libElement.appendChild(bookCard);
    });
    return;
}
html {
    width: 100%;
    height: 100%;
}

body {
    width: inherit;
    height: inherit;
    position: fixed;
    display: flex;
    flex-direction: row;
    justify-content: center;
}

#addToLib {
    width: 175px;
    height: 25px;
    z-index: 1;
}

#form {
    width: fit-content;
    height: 160px;;
    position: absolute;
    left:  0;
    right: 0;
    top: 0;
    bottom: 0;
    margin: auto;
    z-index: 1;
}

form {
    width: inherit;
    height: inherit;
    display: flex;
    flex-direction: column;
    justify-content: space-evenly;
    align-items: center;
    border: solid 1px;
}

label {
    width: 251px;
    height: fit-content;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    padding-left: 10px;
    padding-right: 10px;
}

#readOrNot {
    justify-content: center;
}

#submit {
    width: 125px
}
<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8'>
        <title>JS Library</title>
        <link rel='stylesheet', href='./styles/reset.css', type='text/css', media='all'>
        <link rel='stylesheet', href='./styles/main.css', type='text/css', media='all'>
    </head>
    <body>
        <input id='addToLib', type='submit', name='addToLib', value='Add a book to your library'>
        <div id='library'>

        </div>
        <div id='form' hidden>
            <form>
                <label for='title'>
                    Title:
                    <input type='text', name='title', id='title'>
                </label>
    
                <label for='author'>
                    Author:
                    <input type='text', name='author', id='author'>
                </label>
    
                <label for='numPages'>
                    Pages:
                    <input type='text', name='numPages', id='numPages'>
                </label>
    
                <label id='readOrNot'>
                    Read
                    <input type='radio', name='readAnswer', value='Already read.'>
                    Not read
                    <input type='radio', name='readAnswer', value='Not read yet.'> 
                </label>
    
                <input type='button', name='submitBookInfo', value='Submit book info', id='submit'>
            </form>
        </div>
        <script src='./scripts/book.js'></script>
    </body>
</html>

调用submit()时,我想用表单中的信息创建一个对象,然后将其添加到数组中。随后,我想循环遍历数组,为数组中的每个对象渲染一个'card'DOM元素,然后退出submit()。但是,在第二次使用该表单后,submit()不会在到达return;时退出submit(),而是在函数顶部重新启动并导致向用户显示不需要的错误消息。我已尝试在开发工具中进行调试,但似乎无法弄清楚导致该行为的原因。

javascript html css
2个回答
0
投票

你每次打电话给submitButton.addEventListener()都会打电话给addBookToLibrary()。因此,在添加第二本书之后,提交按钮会两次调用submit()。添加第三本书后,它会调用submit()三次,依此类推。

你应该只在程序开头添加一次这个事件监听器,而不是在addBookToLibrary()里面。

let library = [];
const addToLibButton = document.getElementById('addToLib');

addToLibButton.addEventListener('click', addBookToLibrary);

const submitButton = document.getElementById('submit');
submitButton.addEventListener('click', submit)


function Book(title, author, numPages, read) {
  this.title = title,
    this.author = author,
    this.numPages = numPages,
    this.read = read;
}

Book.prototype.info = function() {
  return [this.title, this.author, this.numPages, this.read]
}

function emptyException(message) {
  this.message = message;
  this.name = 'emptyException';
}

emptyException.prototype.toString = function() {
  return this.name + ': "' + this.message + '" ';
}

function addBookToLibrary() {
  let form = document.getElementById('form');

  alert('Please enter information about the book into the form.');
  form.hidden = false;
}

function submit() {
  let title = document.getElementById('title'),
    author = document.getElementById('author'),
    numPages = document.getElementById('numPages'),
    readOrNot = document.getElementsByName('readAnswer');

  try {
    if (title.value == '' || author.value == '' || numPages == '') {
      throw new emptyException('You cannot leave any fields blank.');
    }
  } catch (err) {
    alert(err.message);
    return;
  }

  readOrNot.forEach(function(radioButton) {
    if (radioButton.checked) {
      readOrNot = radioButton.value;
    }
  });

  library.push(new Book(title.value, author.value, numPages.value, readOrNot));

  title.value = '';
  author.value = '';
  numPages.value = '';
  form.hidden = true;
  clearLibraryContainer();
  render();
}

function clearLibraryContainer() {
  let libElement = document.getElementById('library');
  if (libElement.hasChildNodes()) {
    libElement.childNodes.forEach(function(childNode) {
      childNode.remove();
    });
  }
}

function render() {
  let libElement = document.getElementById('library');

  library.forEach(function(book, index) {
    let bookCard = document.createElement('span');
    bookCard.dataset.arrayIndex = index;

    book.info().forEach(function(info, index) {
      let text = document.createElement('p');
      switch (index) {
        case 0:
          text.innerText = info;
          break;
        case 1:
          text.innerText = `Written by: ${info}`;
          break;
        case 2:
          text.innerText = `${info} pages long.`;
          break;
        default:
          text.innerText = `Status: ${info}`;
          break;
      }
      bookCard.appendChild(text);
    });

    libElement.appendChild(bookCard);
  });
}
html {
  width: 100%;
  height: 100%;
}

body {
  width: inherit;
  height: inherit;
  position: fixed;
  display: flex;
  flex-direction: row;
  justify-content: center;
}

#addToLib {
  width: 175px;
  height: 25px;
  z-index: 1;
}

#form {
  width: fit-content;
  height: 160px;
  ;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  z-index: 1;
}

form {
  width: inherit;
  height: inherit;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: center;
  border: solid 1px;
}

label {
  width: 251px;
  height: fit-content;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  padding-left: 10px;
  padding-right: 10px;
}

#readOrNot {
  justify-content: center;
}

#submit {
  width: 125px
}
<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8'>
  <title>JS Library</title>
  <link rel='stylesheet' , href='./styles/reset.css' , type='text/css' , media='all'>
  <link rel='stylesheet' , href='./styles/main.css' , type='text/css' , media='all'>
</head>

<body>
  <input id='addToLib' , type='submit' , name='addToLib' , value='Add a book to your library'>
  <div id='library'>

  </div>
  <div id='form' hidden>
    <form>
      <label for='title'>
                    Title:
                    <input type='text', name='title', id='title'>
                </label>

      <label for='author'>
                    Author:
                    <input type='text', name='author', id='author'>
                </label>

      <label for='numPages'>
                    Pages:
                    <input type='text', name='numPages', id='numPages'>
                </label>

      <label id='readOrNot'>
                    Read
                    <input type='radio', name='readAnswer', value='Already read.'>
                    Not read
                    <input type='radio', name='readAnswer', value='Not read yet.'> 
                </label>

      <input type='button' , name='submitBookInfo' , value='Submit book info' , id='submit'>
    </form>
  </div>
  <script src='./scripts/book.js'></script>
</body>

</html>

顺便说一句,没有必要把return;放在函数的末尾。到达最后,它会自动返回。如果需要从函数中间返回,则只需要return语句。


0
投票

我不确定你为什么要在function addBookToLibrary()中定义2个函数但是,我认为这是你的问题可能出现的地方。

编辑:分开你的功能并单独打电话(因为输入这个因为某些原因很重要......)

function addBookToLibrary(){
    let form = document.getElementById('form');

    const submitButton = document.getElementById('submit');
    submitButton.addEventListener('click', submit)

    alert('Please enter information about the book into the form.');
    form.hidden = false;
}

function clearLibraryContainer(){
    let libElement = document.getElementById('library');
    if(libElement.hasChildNodes()){
        libElement.childNodes.forEach(function(childNode){
            childNode.remove();
        });
    }
    return;
}

function submit() {
    let title = document.getElementById('title'),
        author = document.getElementById('author'),
        numPages = document.getElementById('numPages'),            
        readOrNot = document.getElementsByName('readAnswer');

    try {
        if(title.value == '' || author.value == '' || numPages == ''){
            throw new emptyException('You cannot leave any fields blank.');
        }
    }
    catch(err){
        alert(err.message);
        return;
    }

    readOrNot.forEach(function(radioButton){
        if(radioButton.checked){
            readOrNot = radioButton.value;
        }
    });

    library.push(new Book(title.value, author.value, numPages.value, readOrNot));

    title.value = '';
    author.value = '';
    numPages.value = '';
    form.hidden = true;
    clearLibraryContainer();
    render();
    return;
}
return;

}

© www.soinside.com 2019 - 2024. All rights reserved.