在切换按钮之前,Vue 不显示使用 v-for 创建的初始元素

Vue not showing initial elements created with v-for until button is toggled

对于我的生活,我无法弄清楚这里发生了什么。它最初工作正常,但当我添加更多代码时它停止了。

我通过 YouTube 教程创建了基本的“图书库”。在我添加更多自己的代码之前,它最初一直在工作。应该发生的是页面应该加载并显示书籍网格(这些当前正在页面加载代码中创建)。书籍数据来自对 google API 的抓取。所有这一切都有效,但是当页面加载时,您会看到它闪烁,然后所有内容都被隐藏,直到我点击“HIDE BOOKS”切换按钮以首先隐藏然后重新显示网格。我还可以使用另一个按钮在列表视图和网格视图之间循环,以使其工作。但我希望无需按任何按钮即可显示图书网格。我所有的标志都设置为真,所以应该显示所有内容。有点难以解释,但代码非常简单。我让它在 js fiddle 上工作,所以你可以看到。

https://jsfiddle.net/jedensuscg/ynmbrauc/1/

HTML

<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="css/styles.css">
    <title>Document</title>
  </head>

  <body>
    <div id="app">
      <button @click="toggleShowBooks">
        <span v-if="showBooks">Hide Books</span> <!-- v-if removes from DOM-->
        <span v-else>Show Books</span>
      </button>

      <button @click="toggleGrid">
        <span v-if="showGrid">List View</span> <!-- v-if removes from DOM-->
        <span v-else>Grid View</span>
      </button>

      <div id="book-display" v-if="showBooks">
        <div id="grid-view" v-if="showGrid">
          <div v-for="book in books" class="box">
            <p></p>
            <h3>{{book.title}}</h3>
            <p> {{book.author}} </p>
            <p> Pages: {{book.pages}} </p>
            <p> Read Book? <span v-if="book.isRead == true">Yes</span> <span v-else="book.isRead == true">No</span></p>
            <img class="book-cover" :src="book.cover" alt="">
          </div>
        </div>

        <ul id="list-view" v-if="!showGrid">
          <li v-for="book in books">
            <h3>{{book.title}}</h3>
            <p> {{book.author}} </p>
            <p> Pages: {{book.pages}} </p>
            <p> Read Book? <span v-if="book.isRead == true">Yes</span> <span v-else="book.isRead == true">No</span>
            </p>
          </li>
        </ul>
      </div>


    <br>
    <br>

    <script src="https://unpkg.com/vue@next"></script>
    <script src="js/app.js"></script>
  </body>

</html>

JS

isbnURL = "https://www.googleapis.com/books/v1/volumes?q=title:";
listDiv = document.querySelector("#list");
titleInput = document.querySelector("#title");
authorInput = document.querySelector("#author");
pagesInput = document.querySelector("#pages");
isReadCheck = document.querySelector("#is-read");

function Book(title, author, isRead = false, pages = 0, isbn = "no isbn", cover = 'no image') {
  this.title = title;
  this.author = author;
  this.pages = pages;
  this.isRead = isRead;
  this.isbn = isbn;
  this.cover = cover;
}

Book.prototype.info = function () {
  isRead = this.isRead ? "Has been read." : "Has not been read";
  return `${this.title} by ${this.author}, ${this.pages} pages. ${isRead}`;
  // return {
  //   title: this.title,
  //   author: this.author,
  //   pages: this.pages,
  //   isRead: this.isRead,
  // };
};

async function getBookInfo(title) {
  let isbn = ''
  let pageCount = ''
  let coverLink = ''
  await fetch(isbnURL + title)
    .then((response) => {
      return response.json();
    })
    .then((data) => {
      isbn = data.items[0].volumeInfo.industryIdentifiers[0].identifier;
      pageCount = data.items[0].volumeInfo.pageCount
      coverLink =  data.items[0].volumeInfo.imageLinks.thumbnail
    })
    .catch((e) => {
      console.log(e);
    });
    return {
      isbn,
      coverLink,
      pageCount
    }
}

async function addBook(title, author, isRead = false) {
  let validBook = true;
  isbn = ''
  library.forEach((book) => {
    if (book.title == title) {
      validBook = false;
    }
  });

  if (validBook) {
    bookData = await getBookInfo(title).then(({isbn, pageCount, coverLink}) => {
      return {
        isbn,
        pageCount,
        coverLink,
      }
    });
    console.log(isbn)
    const newBook = new Book(title, author, isRead, bookData.pageCount, bookData.isbn, bookData.coverLink);
    library.push(newBook);
    console.log(newBook);
  } else {
    console.log("Duplicate Book");
  }
}

addBook("The Hobbit", "J.R.R. Tolkien", true);
addBook("A Game of Thrones", "George R.R Martin", true);
addBook("War and Peace", "Leo Tolstoy", false);
addBook("Harry Potter and the Sorcerers Stone", "J.K Rowling", true);
addBook("Jurassic Park", "Michael Crichton", true);



const app = Vue.createApp({
  data() {
    return {
      showBooks: true,
      showGrid: true,
      books: library,
    };
  },
  mounted: function() {
    
  },
  methods: {
    toggleShowBooks() {
      this.showBooks = !this.showBooks;
    },
    toggleGrid() {
      this.showGrid = !this.showGrid;
      console.log("show grid", this.showGrid);
    },
    consoleLog(text) {
      console.log(text)
    },
    addBook: addBook,
  },
});

app.mount("#app");

一个空的外部数组被设置为您的 books 数据,并且这个外部数组以 Vue 无法检测到的方式异步填充。

addBook 中,更新 books 而不是外部数据:

methods: {
  async addBook(title, author, isRead = false) {
    if(this.books.find(book => book.title == title)) return;

    bookData = await getBookInfo(title).then(({isbn, pageCount, coverLink}) => {
      return {
        isbn,
        pageCount,
        coverLink,
      }
    });
    const newBook = new Book(title, author, isRead, bookData.pageCount, bookData.isbn, bookData.coverLink);
    this.books.push(newBook);
  }
}

并从应用内调用 addBook

created: function() {
  this.addBook("The Hobbit", "J.R.R. Tolkien", true);
  this.addBook("A Game of Thrones", "George R.R Martin", true);
  this.addBook("War and Peace", "Leo Tolstoy", false);
  this.addBook("Harry Potter and the Sorcerers Stone", "J.K Rowling", true);
  this.addBook("Jurassic Park", "Michael Crichton", true);
},

这是更新后的 demo