1️⃣
JavaScript 20 Projects - 1 Quote Generator
前言
這系列是課程 JavaScript Web Projects: 20 Projects to Build Your Portfolio 的筆記,學習利用Javascript 做出各種互動網站。
目標
要做一個名言產生器,利用提供的json檔,搭配按鈕隨機抽選句子,並實作分享到twitter的按鈕。
下面是這次要實作的畫面。範例的連結。
建立 html 內容與 CSS 設定
這邊只提供 HTML 的架構,CSS 就讓大家自由發揮XD。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Quote-generator</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="page">
<div class="header">
<h1 class="title">Quote-Generator</h1>
</div>
<div class="quote-container" id="quote-container">
<div class="quote-text">
<span id="quote"></span>
</div>
<!-- Author -->
<div class="quote-author">
<span id="author"></span>
</div>
<!-- Button -->
<div class="button-container">
<button class="twitter-button" id="twitter" title="Tweet This!">
Share to Twitter
</button>
<button id="new-quote">New Quote</button>
</div>
</div>
</div>
<div class="loader" id="loader"></div>
<!-- Script -->
<script src="script.js"></script>
</body>
</html>
思考 javascript 所需要的動作
- 如何讀入 API?
- 如何隨機產生句子?
- 如何分享到 twitter ?
- 想增加畫面互動的細節,若要增加 loading 時的 Icon,那
- 要如何設定他如何出現與消失?
- 開始與消失要在哪一個 function 中執行?
動作解讀
如何讀入 API?
let apiQuote = [];
async function getQuote() {
const apiUrl = "https://type.fit/api/quotes";
try {
const response = await fetch(apiUrl);
apiQuote = await response.json();
newQuote();
} catch (error) {
// do something
}
}
getQuote();
newQuote()
是下一步驟會建立的 function。
如何隨機產生句子?
接續上步驟讀完資料後的動作,我們來隨機產生句子。
- 先設定來操作HTML元素的DOM。
- 利用Math函數來隨機抽出句子的Object quote。
- 分別設定到對應的HTML內容。
- 並把
newQuote
設定在點擊newQuoteBtn
時觸發的動作。
const quoteContent = document.getElementById("quote");
const authorContent = document.getElementById("author");
const newQuoteBtn = document.getElementById("new-quote");
function newQuote() {
const quote = apiQuote[Math.floor(Math.random() * apiQuote.length)];
authorContent.textContent = quote.author;
quoteContent.textContent = quote.text;
}
newQuoteBtn.addEventListener("click", getQuote);
但這邊有幾個問題要解決:
- 有些句子是沒有作者的,遇到這樣的情形要怎麼處理?
- 若句子的字數太多,可能會讓框框變化太大,可以怎麼處理?
解決方式:
- 若
quote.author
為null
,我們就把它設定為"Unknown”。 - 若字數多於120,幫他添加 class 屬性 "long-quote”,並在CSS 把 "long-quote”的 font-size 屬性值設小一點。
function newQuote() {
const quote = apiQuote[Math.floor(Math.random() * apiQuote.length)];
// console.log(quote);
if (!quote.author) {
authorContent.textContent = "Unknown";
} else {
authorContent.textContent = quote.author;
}
if (quote.text.length > 120) {
quoteContent.classList.add("long-quote");
} else {
quoteContent.classList.remove("long-quote");
}
// Set Quote, Hide Loader
quoteContent.textContent = quote.text;
}
如何分享到 Twitter ?
- 設定來操作twitter button的DOM。
- 利用quoteContent以及authorContent設定要分享的句子與作者變數。
- 利用上述資料設定twitter url。
-
https://twitter.com/intent/tweet?text=
這部分是twitter 分享連結的基本 URL,表示用户正要開始一則新的推文。
-
- 利用
window.open(twitterUrl, "_blank")
方法開新網頁並分享到twitter去。 - 並把
tweetQuote
設定在點擊twitterBtn
時觸發的動作。
const twitterBtn = document.getElementById("twitter");
// Tweet Quote
function tweetQuote() {
const quote = quoteContent.innerText;
const author = authorContent.innerText;
const twitterUrl = `https://twitter.com/intent/tweet?text=${quote} - ${author}`;
window.open(twitterUrl, "_blank");
}
twitterBtn.addEventListener("click", tweetQuote);
增加畫面互動的細節
終於來到最後一步,來看看若要增加 loading 時的Icon,那
- 要如何設定他如何出現與消失?
- 開始與消失要在哪一個function中執行?
解決方式:
要如何設定他如何出現與消失?
- 設定來操作 quoteContainer 以及 loader 的 DOM。
- 要操作 quoteContainer 是因為當 loader 出現時,會希望除了 loader 的其他東西可以先隱藏起來。
- 設定兩個 function,一個是 loading 時,一個是 loading 完成時。分別設定好兩個模式需要隱藏跟顯示的部分。
const quoteContainer = document.getElementById("quote-container");
const loader = document.getElementById("loader");
// Loading Spinner Shown
function loading() {
loader.hidden = false;
quoteContainer.hidden = true;
}
// Remove Loading Spinner
function complete() {
quoteContainer.hidden = false;
loader.hidden = true;
}
開始與消失要在哪一個 function 中執行?
我們選擇的是 newQuote()
,因為在他隨機產生句子的過程中,我們還需要針對句子的狀況做畫面跟內容的調整,而我們希望這部分是可以忽略掉的,所以在這個function開始與結束的地方,分別插入 loading()
跟 complete()
來達成loading的效果。
function newQuote() {
loading();
const quote = apiQuote[Math.floor(Math.random() * apiQuote.length)];
// console.log(quote);
if (!quote.author) {
authorContent.textContent = "Unknown";
} else {
authorContent.textContent = quote.author;
}
if (quote.text.length > 120) {
quoteContent.classList.add("long-quote");
} else {
quoteContent.classList.remove("long-quote");
}
// Set Quote, Hide Loader
quoteContent.textContent = quote.text;
complete();
}
最終 Javascript 的程式碼
const quoteContainer = document.getElementById("quote-container");
const quoteContent = document.getElementById("quote");
const authorContent = document.getElementById("author");
const newQuoteBtn = document.getElementById("new-quote");
const loader = document.getElementById("loader");
const twitterBtn = document.getElementById("twitter");
let apiQuote = [];
// Loading Spinner Shown
function loading() {
loader.hidden = false;
quoteContainer.hidden = true;
}
// Remove Loading Spinner
function complete() {
quoteContainer.hidden = false;
loader.hidden = true;
}
function newQuote() {
loading();
const quote = apiQuote[Math.floor(Math.random() * apiQuote.length)];
// console.log(quote);
if (!quote.author) {
authorContent.textContent = "Unknown";
} else {
authorContent.textContent = quote.author;
}
if (quote.text.length > 120) {
quoteContent.classList.add("long-quote");
} else {
quoteContent.classList.remove("long-quote");
}
// Set Quote, Hide Loader
quoteContent.textContent = quote.text;
complete();
}
async function getQuote() {
const apiUrl = "https://type.fit/api/quotes";
try {
const response = await fetch(apiUrl);
apiQuote = await response.json();
newQuote();
} catch (error) {
// do something
}
}
// Tweet Quote
function tweetQuote() {
const quote = quoteContent.innerText;
const author = authorContent.innerText;
const twitterUrl = `https://twitter.com/intent/tweet?text=${quote} - ${author}`;
window.open(twitterUrl, "_blank");
}
newQuoteBtn.addEventListener("click", getQuote);
twitterBtn.addEventListener("click", tweetQuote);
getQuote();
Discussion