javascript - 导致不需要的递归行为的 JavaScript 函数错误

标签 javascript html css

我有一个隐藏表单,其中包含一些文本字段和一个触发 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()的功能,并导致向用户显示不需要的错误消息。我曾尝试在开发工具中进行调试,但似乎无法弄清楚是什么导致了这种行为。

最佳答案

每次调用 addBookToLibrary() 时,您都在调用 submitButton.addEventListener()。因此,在您添加第二本书后,提交按钮会调用 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 语句。

关于javascript - 导致不需要的递归行为的 JavaScript 函数错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55768460/

相关文章:

javascript - 将 javascript 变量传递给代码隐藏

javascript - 单边倾斜 div 四周的边框

css - 为什么页脚没有粘在底部?

html - 左对齐框不会留在父 div 中

javascript - jQuery 和 Restful Web 服务安全

javascript - 拖放上传插件

JQuery 计算子元素并使用 if 语句修改 CSS

javascript - 定位给定标签的所有最后(但不是最后)元素

javascript - 扩展 jQuery UI Accordion 后,谷歌地图不再以其他 map 为中心

javascript - gulp - 如何停止或取消任务运行