上一章我們實(shí)現(xiàn)了最基本的游戲界面和游戲的簡(jiǎn)單入口,這一章,我們完善和制作 排行榜 功能,并為將來(lái)游戲結(jié)束時(shí)使用、記錄排行榜提供支持。
在使用 互聯(lián)網(wǎng) 的時(shí)候,我們基本上離不開(kāi) 瀏覽器 ( browser ) 。 瀏覽器其實(shí)可以看作一個(gè) 中間人,他將 用戶無(wú)法理解、看不太懂的 腳本語(yǔ)言描述的程序,轉(zhuǎn)換為 用戶可以看得到的界面、接收用戶的輸入輸出動(dòng)作,并通過(guò)執(zhí)行腳本程序給出對(duì)應(yīng)的反饋。 一般,我們把前面的 “轉(zhuǎn)換為界面” 過(guò)程稱作 “渲染” (render)。 在上一章中,我們?cè)?.html 文件中填寫(xiě)了代碼,在瀏覽器中打開(kāi)這個(gè)文件,看到了界面,我們姑且稱這個(gè)“渲染”動(dòng)作為“靜態(tài)渲染”,那么這一章中,我們將會(huì)看到另外一種“動(dòng)態(tài)渲染”。
在程序開(kāi)發(fā)過(guò)程當(dāng)中,我們一般會(huì)提到“接口”,“封裝”等等概念。我理解,提出這些概念的目的,其實(shí)是在告訴我們,將程序?qū)懙母扒逦币恍?。這個(gè)“清晰”一般可以描述為兩方面:
定義“接口”,即就是將完整的、能夠重復(fù)使用的“功能”包裝(封裝)成函數(shù)、對(duì)象,并供其他邏輯 或 在其他地方調(diào)用;使用者并不需要了解“接口”內(nèi)部具體的實(shí)現(xiàn)邏輯,只需知道接口“形式”即可使用,完成對(duì)應(yīng)的功能,同時(shí)使用者 不需要對(duì)其不需了解的事情加以干涉 。我們下面也會(huì)封裝、實(shí)現(xiàn)一些簡(jiǎn)單的接口來(lái)介紹上面的概念。
按照網(wǎng)頁(yè)的開(kāi)發(fā)方式,我一般習(xí)慣按照“基本結(jié)構(gòu)”->“外觀潤(rùn)色”->“行為功能”這個(gè)流程進(jìn)行進(jìn)行開(kāi)發(fā)。首先,在排行榜(上一章中 (3) 的位置)加入下面“基本結(jié)構(gòu)”的 HTML 代碼:
標(biāo)簽,并用 來(lái)表示一行, 或 分別來(lái)表達(dá) 表頭和表體 中的單元格。 上面元素對(duì)應(yīng)的屬性 class 中使用的對(duì)應(yīng)內(nèi)容,可暫不關(guān)心(有興趣的同學(xué),可以 參看 中文 或 英文 的文檔)
上述代碼我們建立了一個(gè)基本的“表”,并為表體元素起名為 rank_table 便于將來(lái)對(duì)其進(jìn)行操作(如,加入實(shí)際展示的數(shù)據(jù),刷新排行榜等)。
因?yàn)槲覀儗?duì)上層 元素設(shè)置了 text-align: center 居中對(duì)齊,表格對(duì)齊(標(biāo)題被設(shè)置為左對(duì)齊了,內(nèi)容區(qū)域是居中對(duì)齊的)有點(diǎn)亂,需要加入下面 CSS 樣式( minesweeper.css 文件中):
.block.rank .table tbody td { /* 排行榜表格內(nèi)容居左(由于上層元素設(shè)置了 居中) */ text-align: left; /* left - 左對(duì)齊 right - 右對(duì)齊 center - 居中 */}
CSS 中存在樣式的“繼承”,即父級(jí)元素設(shè)置的樣式,如果適用的化,會(huì)被“繼承”應(yīng)用的子元素上。
所謂適用的樣式有很多,例如 字體名 font-family 、字體大小 font-size 、顏色 color ,當(dāng)然也存在一些特殊情況,這些屬性不會(huì)被繼承,例如:
這個(gè) A 標(biāo)簽的顏色不繼承 動(dòng)態(tài)渲染 編寫(xiě) minesweeper-rank.js 文件,我們使用 JavaScript 程序?yàn)楸砀窦尤雰?nèi)容,并“ 渲染 ”出來(lái):
(function($) { // 位置:(A) var data = [ {name:"DemoUserA", time:200}, // 直接使用 XXX 秒 來(lái)描述 耗時(shí) {name:"DemoUserB", time:300}, // 展示的時(shí)候用程序?qū)⑵渥優(yōu)?XX 分 XX 秒的形式 {name:"DemoUserC", time:400}, ] // 我們定義 $ 開(kāi)頭的變臉用來(lái)記錄要操作的元素 var $table = $("#rank_table") // 排行榜的 “渲染” function render() { $table.empty() // 清空表格中目前的內(nèi)容 for(var i=0;i"+(i+1)+" "+data[i].name // 一行太長(zhǎng),可以換行寫(xiě) +" "+renderTime(data[i].time) // this 這里指得就是當(dāng)前 排行榜對(duì)象 rank // 調(diào)用 renderTime 函數(shù)生成 XX分XX秒 形式的文本 +" ") // ! 加入內(nèi)容,其實(shí)就是將 HTML 代碼文本 `append()` 添加到表格體中 } } // XXX 秒 => XX 分 XX 秒 function renderTime(time) { return parseInt(time/60) + " 分 " + (time % 60) + " 秒" } // 刷新頁(yè)面時(shí)立刻進(jìn)行“渲染” rank.render() // 位置:(B)}(jQuery))
JavaScript 中可以使用 [ ... ] 形式定義數(shù)組,使用 {XXX: YYYY, XXX: YYYY} 形式定義對(duì)象;
數(shù)組一般使用 下標(biāo)形式訪問(wèn),例如 data[i] ;
對(duì)象一般使用 .name 形式訪問(wèn),例如 data[i] 是一個(gè)對(duì)象,可以用 data[i].name 來(lái)訪問(wèn)其姓名屬性;
持久化 為了讓排行榜能夠記錄并保留數(shù)據(jù)(不在刷新后消失),我們參照第一章 使用 localStorage 對(duì)象提供的功能來(lái)完成。我們將 (A) 處初始化的代碼改為:
// 位置: (A)var data = localStorage.getItem("rank_data")if(!data) { data = [ // 為演示方便,我們初始化一些數(shù)據(jù) {name:"DemoUserA",time:200}, // 我們直接使用 XXX 秒 來(lái)描述用時(shí) {name:"DemoUserB",time:300}, // 我們直接使用 XXX 秒 來(lái)描述用時(shí) {name:"DemoUserC",time:400}, // 我們直接使用 XXX 秒 來(lái)描述用時(shí) ] // 我們不能直接包數(shù)組數(shù)據(jù)保存到 localStorage 中,需要對(duì)他進(jìn)行“序列化”,即將起變成文本; localStorage.setItem( "rank_data", JSON.stringify(data) ) // 在 JavaScript 中一般使用 JSON.stringify(obj) 將 obj 變?yōu)槲谋拘问揭员愦鎯?chǔ) // 這種“變文本”的過(guò)程就是“序列化”}else{ // 保存了數(shù)據(jù),讀取出來(lái)后需要“還原”: // 由于我們保存的是“序列化”的數(shù)據(jù),我們需要將它“反序列化” data = JSON.parse(data) // JSON.parse() 與 上面 JSON.stringify() 對(duì)應(yīng),用于還原已經(jīng)“序列化”的文本到其原始值}
JSON 與 localStorage 類似,也是由瀏覽器提供的進(jìn)行數(shù)據(jù)“序列化”、“反序列化”的函數(shù)對(duì)象。 同時(shí) JSON 也是一種文本描述數(shù)據(jù)的形式,具體說(shuō)明可以參考 http://www.json.org/json-zh.html ;
同時(shí) JSON 是目前最流行的數(shù)據(jù)交換方式的一種,尤其在服務(wù)器端與瀏覽器交互的“數(shù)據(jù)型接口”中被大量應(yīng)用。例如大家熟知的 微信公眾平臺(tái),就提供了 JSON 形式的接口,有興趣的同學(xué)可以看看他們的文檔 https://mp.weixin.qq.com/wiki ;
我們可以在瀏覽器中打開(kāi)網(wǎng)頁(yè),并按 F12 鍵打開(kāi)調(diào)試界面,在 Resource 面板中,找到 localStorage 項(xiàng),可以看到我們的程序已經(jīng)將數(shù)據(jù)成功的寫(xiě)入了:
大家可以嘗試通過(guò)這個(gè)面板修改 localStorage 的內(nèi)容,刷新頁(yè)面后會(huì)發(fā)現(xiàn)展示的內(nèi)容也會(huì)隨之發(fā)生變化。
接口 到這里,我們?yōu)榕判邪穸x的界面和基本顯示功能就完成了。但是,這個(gè)排行榜還沒(méi)有辦法 動(dòng)態(tài)的調(diào)整 ,即將來(lái)在實(shí)際游戲完成的時(shí)候,我們需要把當(dāng)前名稱的用戶成績(jī)“更新”或“加入”到排行榜里面。雖然是將來(lái),我們需要先為游戲結(jié)束做進(jìn)行這個(gè)功能時(shí)留下接口。
我們可能需要提供很多這些類似的“接口”,我們把這種接口統(tǒng)一放在一個(gè)名為 MineSweeperRank 的全局對(duì)象中(在位置 (B) 處加入下面的代碼):
// 位置:(B)window.MineSweeperRank = { // window 為全局命名空間,同時(shí)也代表了瀏覽器當(dāng)前打開(kāi)網(wǎng)頁(yè)的窗口 // 接口1. 加入用戶及成績(jī)進(jìn)入榜單 appendUserRank: function(name, time) { // 將成績(jī)插入到 data 中的合適位置 // 從后往前,找到用時(shí)小于當(dāng)前 time 的地方 for(var i=data.length-1; i>=0; --i) { if(data[i].time < time) { data.splice(i + 1, 0, {"name": name, "time": time}) // 從 i + 1 這個(gè)位置開(kāi)始,刪除 0 個(gè)元素,加入 新增元素 break // 找到了速度更快的記錄,跳出循環(huán)(這時(shí) i 應(yīng)該還小于 data.length) } } if(i == data.length) { // 沒(méi)有找到比當(dāng)前值更小的了,直接排在第一名 data.unshift({"name": name, "time": time}) } // 截取 data 的前 6 項(xiàng)(不要讓排行榜太長(zhǎng)了) data = data.slice(0, 6) // 數(shù)據(jù)更新了,我們需要對(duì)應(yīng)更新界面,即重新渲染 render() // 保存數(shù)據(jù) localStorage.setItem( "rank_data", JSON.stringify(data) ) }, // 接口2. 清理(清空)榜單 clearRank: function() { data.splice(0, data.length) // 數(shù)據(jù)更新了,我們需要對(duì)應(yīng)更新界面,即重新渲染 render() // 保存數(shù)據(jù) localStorage.setItem( "rank_data", JSON.stringify(data) ) }, // 接口3. } 上面函數(shù)目前沒(méi)有實(shí)際的調(diào)用者,我們可以在 “開(kāi)發(fā)者工具” ( F12 ) 的 Console 界面中輸入調(diào)用代碼(例如: MineSweeperRank.appendUserRank("Terry",450) ) 嘗試調(diào)用,看看效果:
從分工明確的角度,我們也給 “入口” 增加 “接口” 功能,我們將 “獲取用戶輸入的名字” 和 “開(kāi)始游戲” 作為 “接口” 封裝。 注意,前者與上述 排行榜 接口 類似,是“調(diào)用”方式的接口。而后者,則是“ 觸發(fā) ”形式的接口。
我們先將“調(diào)用”形式的接口實(shí)現(xiàn)(調(diào)整 minesweeper-entry.js 文件, 在結(jié)束行函數(shù)大括號(hào)內(nèi),補(bǔ)充如下代碼):
// 位置 (C)// 對(duì)外接口window.MineSweeperEntry = { // 接口1. 獲取當(dāng)前用戶名 getName: function() { return localStorage.getItem("entry_input_name") || "無(wú)名氏" }, }// 位置 (D)
JavaScript 使用 || 表示 “邏輯或”,但與其他部分語(yǔ)言不同, || 返回的并非是 “布爾值”,而是條件中 第一個(gè) 真 值;
對(duì)應(yīng)的還存在 && 標(biāo)識(shí) “邏輯與”,也同樣存在上面的使用方式,返回第一個(gè) 假 值,例如: var a = true && 0 變量 a 的值為 0 而非 false;
從分工上說(shuō),我們將 獲取姓名 接口定義在 “入口”,從 職責(zé)上說(shuō) 我們將 “未輸入姓名,處理為 ‘無(wú)名氏’” 這個(gè)邏輯封裝在了接口內(nèi)部,使用者就不用關(guān)心了。
請(qǐng)大家嘗試使用 Chrome 瀏覽器提供的 開(kāi)發(fā)者工具 ( F12 或菜單 三 -> 更多工具 -> 開(kāi)發(fā)者工具 )。它能夠提供界面元素 (HTML/CSS) 的調(diào)試、 代碼(JavaScript)調(diào)試,頁(yè)面性能測(cè)試,網(wǎng)絡(luò)監(jiān)控等等功能,甚至很多功能連一些正式的前端開(kāi)發(fā)人員都不太了解。有興趣的同學(xué)可以去看看 http://devtoolstips.com/ ,這個(gè)網(wǎng)站總結(jié)和演示了很多開(kāi)發(fā)者工具的使用技巧,值得學(xué)習(xí)。
附件 本章目前完成的完整代碼可以在這里下載壓縮包
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com
(二)排行榜(定義和使用函數(shù)、對(duì)象)-掃雷網(wǎng)頁(yè)小游戲_html/css_WEB-ITnose
(二)排行榜(定義和使用函數(shù)、對(duì)象)-掃雷網(wǎng)頁(yè)小游戲_html/css_WEB-ITnose:上一章我們實(shí)現(xiàn)了最基本的游戲界面和游戲的簡(jiǎn)單入口,這一章,我們完善和制作 排行榜 功能,并為將來(lái)游戲結(jié)束時(shí)使用、記錄排行榜提供支持。 在使用 互聯(lián)網(wǎng) 的時(shí)候,我們基本上離不開(kāi) 瀏覽器 ( browser ) 。 瀏覽器其實(shí)可以看作一個(gè) 中間人,他將 用戶無(wú)
Top