javascript - Vue 不显示使用 v-for 创建的初始元素,直到按钮被切换
问题描述
对于我的生活,我无法弄清楚这里发生了什么。它最初可以工作,但是当我添加更多代码时它停止了。
我有通过 youtube 教程创建的基本“图书库”。它最初是有效的,直到我添加了更多我自己的代码。应该发生的是页面应该加载并显示书籍网格(这些书籍目前正在页面加载的代码中创建)。图书数据来自对谷歌 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);
},
这是更新的演示
推荐阅读
- php - Laravel + Swift Mailer:错误:没有有效的收件人
- postgresql - 在 PostgresSQL 函数中,是否可以检查列值是否与给定参数值匹配?
- php - Google Ads 无法在 Multi-park 域网站上运行
- javascript - 检查输入字符串是否只有数字且最大长度为 4
- docker - 阻止服务不受限制地在某些工作人员上运行
- kubernetes - Vagrant:在所有虚拟机启动后运行 Ansible 配置,Ansible 无法连接到所有主机
- ios - 单击通知而不是通知操作时打开输入文本字段
- mysql - 获取由 Sequelize Association 生成的错误查询
- server - 显示 DNS_PROBE_FINISHED_NXDOMAIN 的错误消息
- google-cloud-storage - 从没有互联网的云存储桶下载