JQuery assignment
The Box Fixer (12/2 version)
還記得前幾堂課我們一直用到的box嗎
現在,因為來自古老東方的奇幻神秘力量
四個box - 文具箱、玩具箱、工具箱以及嚇人箱
就這樣出現在你的房間裡
突然,你的耳邊傳來神秘人的聲喚...
神秘人:「醒醒阿肥宅,你知道你多久沒整理房間了嗎?」
你:「呃...這是演哪齣?」
神秘人:「你不需要知道我是誰,你只要知道,現在要是不快點整理妳的房間裡那些充滿神秘力量的box們,等你一入睡,那些box們就會化身成為期末59小精靈纏著你!就問你怕不怕?」
你:「我不怕,就算當了一個我,還有千千萬萬個我。」
聽見你充滿自信的回答,神秘人的聲音就這樣消失了
但,實際上,你還是很在意期末59小精靈
於是,你還是決定遵從神秘人的指示
打開repl,架設好jquery環境
踏上了整理神秘boxes的旅程...
由於每天都盯著電腦
慢慢對整個房間感到陌生了
於是,眼觀四面、耳聽八方,環顧四周的你
感慨了聲:「啊~原來是長這樣子阿」
<!-- Place below code in index.html -->
<div id="room"></div>/* Place below code in style.css */
* {
box-sizing: border-box;
}
body {
background: #222;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
font-family: "微軟正黑體";
}
#room {
display: flex;
flex-wrap: wrap;
width: 600px;
height: 600px;
margin: 0 auto;
padding: 4px;
}再來,你開始找尋在房間裡散落的神秘箱子
並打算以下面的設計圖將箱子聚集在一起
才好方便整理
但由於箱子是神祕的
其既存在又不存在
其真實的存在(骨架)得靠自己來塑照
<!-- Place below structure in index.html -->
<div id="box-template" class="box">
<h2 class="title">A box</h2>
<ul class="items"></ul>
</div>神秘箱子可能是藍色圓形的,也可能是綠色方形的
無論如何,讓自己來決定樣式總是一定行
/* Place below code in style.css file */
.box {
position: relative;
width: calc(50% - 6px);
height: calc(50% - 6px);
margin: 3px;
background: #9ED9EB;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3), 0 0 20px rgba(0, 0, 0, 0.1) inset;
border-radius: 5px;
}
.box:before {
position: absolute;
content: "";
box-shadow: 0 10px 25px 20px #518C96;
top: 40px;
left: 14px;
bottom: 50px;
width: 15%;
z-index: -1;
transform: rotate(-8deg);
}
.box:after {
position: absolute;
content: "";
box-shadow: 0 10px 25px 20px #518C96;
top: 40px;
right: 14px;
left: auto;
bottom: 50px;
width: 15%;
z-index: -1;
transform: rotate(8deg);
}
.box .title {
text-align: center;
}
.box .items {
width: 85%;
height: 120px;
margin: 0 auto;
padding-top: 8px;
border: 2px dashed #F7EEEE;
border-radius: 5px;
}神秘箱子感應到其即將有形體可以依附
於是,boxes的資訊傳入了你的腦中
// Place below code in script.js
var boxes = [
{
name: "文具箱",
items: [
{ name: "百樂原子筆", owner: "文具箱" },
{ name: "死亡筆記本", owner: "文具箱" },
{ name: "尖叫雞", owner: "玩具箱" }
]
},
{
name: "玩具箱",
items: [
{ name: "泰迪熊", owner: "玩具箱" },
{ name: "一打L夾", owner: "文具箱" },
{ name: "放三個月的百香果", owner: "嚇人箱" }
]
},
{
name: "工具箱",
items: [
{ name: "羅賴把", owner: "工具箱" },
{ name: "熱熔槍", owner: "工具箱" },
{ name: "UNO", owner: "玩具箱" }
]
},
{
name: "嚇人箱",
items: [
{ name: "你沒有女朋友", owner: "嚇人箱" },
{ name: "萬用工具人", owner: "工具箱" },
{ name: "熱騰騰的紅字成績單", owner: "嚇人箱" }
]
}
];萬事起頭難
你開始試著形體化第一個神秘箱子 - part1
// Place below code in script.js
// 以下所有跟DOM有關的變數皆會以dom_開頭以識別用
// 先從畫面下手,使用一個id為box-template的box來複製箱子,要記得刪除複製出來的id,因為id是唯一的
var dom_box = $("#box-template").clone();
dom_box.removeAttr("id");
// 在JS陣列中取得第一個box的資訊,並以下面步驟,試著將其形體化
var box = boxes[0];
/*
使用 $(selector).find(child_selector) 找到box名稱欄位,
find是traversal操作,回傳的也是一個jquery element,也就是 $(selector),
再使用 $(selector).text(some_text) 填入box名稱
*/
var dom_box_title= dom_box.find("<名稱欄位selector>");
dom_box_title.text("<箱子名稱>");
試著形體化第一個神秘箱子 - part2
// Place below code in script.js
// 再來對箱子內物品做處理,要把東西放進箱子裡
var dom_box_items = dom_box.find("<物品空間selector>");
// 先取得箱子中的物品陣列
var box_items = box.items;
// 使用for-loop,將資料中的物品們一一轉換成html element,再將其放入箱子裡
for (var j = 0; j < box_items.length; j++) {
var item = box_items[j];
var temp_item = "<li class=\"item\">" + item.name + "</li>"; // *註1*
dom_box_items.append(temp_item);
}
/*
最後,請把第一個box放入房間,
$(selector).append()可以接受html element字串,或是jquery element
*/
$("#room").append("<第一個箱子>");
/*
註1: 一般html element,其屬性value會以一對雙引號包起來,<div class="xxx"></div>
在程式中若外層有字串處理,且已有使用雙引號,則內部雙引號必須採用 → \",
或是直接使用單引號 → ',
e.g. "<li class=\"item\">" or "<li class='item'>"
*/試著形體化第一個神秘箱子 - part3
/* Place below code in style.css */
/* 由於第一個箱子出現了,作為template的box已經沒有出現的必要,故將其隱藏 */
#box-template {
display: none;
}試著形體化所有神秘箱子
// Place below code in script.js
// 這次,我們要一次解決四個箱子,所以需要改寫一下
for (var i = 0; i < boxes.length; i++) {
// 前幾步驟的code
}發現for中有for了嗎?
這叫做nested loop,也就是「巢狀迴圈」
別擔心,這邊我們僅僅使用基本款
只要內外層loop的參數不要相撞即可
(外層用i,內層就用j,反之亦然)
可是為什麼要巢狀迴圈呢?
請語意上思考一下~
確認每項物品是不是放在對的箱子
對的標綠、錯的標紅
// Place below code in script.js
for (var j = 0; j < box_items.length; j++) {
var item = box_items[j];
var temp_item = "<li class=\"item\">" + item.name + "</li>";
var itemClass = ???; // 請使用getItemClass函式來取得判斷class
dom_box_items.append(temp_item);
/*
在物品被插入到html後,才能使用jquery去取得該element,
經由getItemClass可以得到物品是否放對箱子的判斷class,
使用 $(selector).addClass(some_class) 來為item增加class
*/
var dom_item = dom_box_items.find(".item:last-child");
$(dom_item).addClass(itemClass);
}
// Don't move this function
function getItemClass(box_name, item_box_name) {
return box_name === item_box_name ? "correct" : "incorrect";
}/* Place below code in style.css */
.correct {
color: green;
}
.incorrect {
color: red;
}更進一步,讓我們從箱子名稱就能辨識箱子是否整理好
// Place below code in script.js
/*
先假設箱子是整理好的,在items的for-loop中,
只要任一item沒放對箱子,那這箱子便不是整理好的
*/
var box_is_correct = true; // 宣告一Boolean
for (var j = 0; j < box_items.length; j++) {
/*
...
*/
var itemClass = getItemClass(box.name, item.owner);
if (itemClass == "incorrect") {
box_is_correct = false;
}
/*
...
*/
}
/*
請使用if-else,判斷 box_is_correct 是否正確時,分別為箱子名稱增加正確的樣式,
一樣錯的標紅、錯的標綠;
此外,針對未整理好的箱子,其名稱再使用 $(selector).css("property", "value");
將其font-style設為italic(斜體)
*/
if (箱子整理好) {
dom_box_title.addClass("<正確的class名稱>");
} else {
dom_box_title.addClass("<不正確的class名稱>");
dom_box_title.css("自己試");
}
看來樣式部分都搞定了,來整理箱子吧
// Place below code in script.js
// 注意到每個箱子中都有不屬於其箱子的物品
// 請宣告一函式叫做 shuffle ,其中使用for-loop對每個箱子做處理
function shuffle() {
// 這邊一樣是nested loop,試試看吧
for (...) {
var box = boxes[i];
var box_items = box.items;
var correctItems = []; // 宣告一個新的items,概念上請類比把正確物品先放在地板上
for (...) {
var box_item = box_items[j];
if (box.name == box_item.owner) {
// 請把正確的先放到地板上
correctItems...
} else {
// 錯的則使用array的find方法找到對應該物品的箱子(跟jquery的find不一樣,別搞混了)
var which_box = boxes.find(function(box) { return box.name == item.owner; });
// 然後直接放進該箱子
which_box...
}
}
// 把地板上、正確的物品放回去
box.items = correctItems;
});
console.log("整理過後: ", boxes); // 來確認結果是否正確
}
// 雖然解出來了,但解法好像有點兒彆扭?試著用別的想法來解!!在畫面上加個進行「整理」的button
// Place below code in script.js
// 沒有名稱的function,稱作匿名函式,因為其名稱並不重要,我們只需要它執行裡面的工作
$("#btn-shuffle").click(function () { shuffle(); });/* Place below code in style.css */
#btn-shuffle {
position: fixed;
left: calc(50% + 1.5px);
top: calc(50% + 9px);
transform: translate3d(-50%, -50%, 0);
z-index: 2;
width: 80px;
height: 80px;
border: 1px solid #e1e1e1;
border-radius: 50%;
font-size: 16px;
cursor: pointer;
background: aliceblue;
}<!-- Place below structure in index.html -->
<body>
<button id="btn-shuffle">整理</button>
<!-- 其餘不動 -->
</body>嘿!等等,畫面上並沒有改變阿
沒錯,除了改變boxes陣列
我們還需要更新DOM - part1
// Place below code in script.js
// 宣告一函式 reRender
function reRender() {
// 基本上長得跟最前面幾step很像,但這次我們只需要修改值,不需要重新append箱子到room裡
for (var i = 0; i < boxes.length; i++) {
var dom_box = $(`.box:nth-child(${i + 1})`);
var dom_box_title = dom_box.find(".title")
var box = boxes[i];
var dom_box_items = dom_box.find(".items");
dom_box_items.empty(); // 使用 $(selector).empty() 先清空原本的items,下方再append正確的回去
var box_items = box.items;
var box_is_correct = true;
for (var j = 0; j < box_items.length; j++) {
var item = box_items[j];
var temp_item = "<li class=\"item\">" + item.name + "</li>";
var itemClass = getItemClass(box.name, item.owner);
if (itemClass == "incorrect") {
box_is_correct = false;
}
dom_box_items.append(temp_item);
var dom_item = dom_box_items.find(".item:last-child");
$(dom_item).addClass(itemClass);
}
if (!box_is_correct) {
dom_box_title.addClass("incorrect");
dom_box_title.css("font-style", "italic");
} else {
dom_box_title.addClass("correct");
}
}
}更新DOM - part2
好像哪裡不對?為什麼箱子名稱樣式還是錯的QQ?
// Place below code in script.js
// 宣告一函式 reRender
function reRender() {
for (var i = 0; i < boxes.length; i++) {
// ...
for (var j = 0; j < box_items.length; j++) {
// ...
}
/*
由於重新被append的只有items,標題還是原樣,
也就是說一開始使用 $(selector).addClass(some_class) 的狀態會保留,
所以我們需要先使用 $(selector).removeClass(some_class) 來移除其原本class,
然後才進行 $(selector).addClass(some_class)。
$(selector).css() 亦是同理,正確的箱子名稱無須斜體,請把font-style改回normal
*/
if (!box_is_correct) {
dom_box_title.removeClass("???").addClass("incorrect");
dom_box_title.css("font-style", "italic");
} else {
dom_box_title.removeClass("???").addClass("correct");
dom_box_title.css("font-style", "???");
}
}
}Congratulations
請分享你的成果吧~~
jq_assignment
By David Tsui
jq_assignment
- 303