JavaScript CSS3

Javascript 動態網頁程式設計 - 上課教材

動畫互動網頁程式設計 > 課程內容 > 第 06 章 - 陣列與字串應用

第 06 章 - 陣列與字串應用

上次更新日期 2020/10/07

從資料庫課程我們也會知道,網頁的資料展示經常離不開『陣列』這玩意兒!而如果每次都要將資料丟給系統來進行資料庫的運算, 好像也會產生比較嚴重的伺服器負荷。因此,如果能夠將來自資料庫的陣列改以 javascript 的陣列格式來丟給用戶, 然後用戶可以在自己的瀏覽器上面自行透過 javascript 的功能來展示資料的不同展示情境,將有助於降低伺服器的負荷。 另外,某些時候使用者可能要從本地端將資料上傳到網頁上,讓網頁來進行資料的分析,這也能透過簡單的字串處理搞定!

學習目標:

  1. 了解 javascript 的陣列宣告與使用
  2. 透過文字解析帶入陣列應用
  3. 其他陣列應用效果

6.1: javascript 陣列宣告與使用

陣列就是設定某一個名稱的變數,這個變數其實是個『大櫃子』這個櫃子裡面有多個『小抽屜』,每個抽屜都會有編號。假設櫃子名稱為 myarray, 而抽屜有 5 個,從 0 開始編號,那麼,我們就會有底下的變數代號:

myarray[0] = 'content0';
myarray[1] = 'content1';
myarray[2] = 'content2';
myarray[3] = 'content3';
myarray[4] = 'content4';

所以,當你要打開第一個小抽屜時,那就是取用 myarray[0] 這個變數的內容之意。意思是這樣,但是如何宣告陣列呢?

  • 宣告空的陣列

javascript 的陣列宣告方式非常多!假如你不知道你的陣列長度 (就是小抽屜的數量) 有多少,那就先宣告一個空的陣列,然後慢慢將資料填進去即可。 例如底下的模樣:

var myarray = [];
myarray[0] = 'content0';
...
  • 預設陣列的內容數量

如果你知道你的陣列有幾個,例如有 9 個資料 (小抽屜),那麼就可以先宣告個數:

var myarray = New Array(9);
  • 已經知道陣列內容,直接指定陣列內容即可 (最常用)

如果你已經知道陣列的內容,並且內容資料已經以逗號 (,) 分隔了,那直接設定是最快的方式:

var myarray = [ 'content1', 'content2', 'content3' ...];

至於陣列常用的方法 (Method) 有:

myarray.length                    // 回傳陣列長度,亦即有幾個小抽屜的意思
myarray.push('new_content')       // 在陣列的尾端加入一筆新的陣列值,亦即增加一個小抽屜
myarray.pop()                     // 與 .push 相反,刪除最後一筆值,亦即拿掉最後一個小抽屜
myarray.shift()                   // 與 .pop 相似,刪除第一筆值,亦即拿掉第一個小抽屜
myarray.sort()                    // 將資料進行排序,從小到大排序
myarray.sort(); myarray.reverse() // 反向排序,從大到小排序
myarray.forEach( function(myvar) { alter(myvar) } )    // 將陣列內容以 myvar 為變數名稱,一個一個執行迴圈

光說不練也不行,現在就讓我們來處理一下,是否能夠設定好陣列後,將資料直接顯示出來?

例題 6-1-1:設定好陣列後,將陣列內容用不同的方式印出來到螢幕上
  1. 建立新檔 unit06-1-1.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案的內容 寫入 unit06-1-1.php 當中,並查閱一下網頁的內容
  3. 撰寫 mod2() 函數,大致的內容大概是:
    • 設定名為 msg 的變數,內容先指定為空字串
    • 使用『 myarray.forEach( function(gogo) { msg = msg + gogo ; } ); 』的方式,讓資料一直累加出來。
    • 承上,其實上面的資料一直輸出內容,請以『清單』的方式將資料輸出較佳。
    • 最後,讓 mod2 的 id 元素的 innerHTML 變成 msg 即可。
  4. 自己嘗試撰寫出 mod1() 函數,內容大致是:
    • 宣告變數 i 即可,不用給值。
    • 設定名為 msg 的變數,內容先指定為空字串
    • 使用 for 迴圈,項目請自己指定,主要透過 i 的變化與 myarray 的『長度』來處理
    • 其他的項目與 mod2() 相仿。
印出陣列的內容
  • 不會重複的上台名單

在前一章節的上台抽抽樂過程中,我們抽出來的名單很可能會『重複』喔!如果你有多做幾次的話,就會發現了。這樣不合理啊! 所以,能不能抽出來的名單給予第二層判定,當有重複的名單,就重新抽一次?基本上是沒問題啊!就透過 for 固定迴圈去設計抽獎人數, 然後透過 while 迴圈去判斷有沒有重複的名單即可。

例題 6-1-2:不會重複的抽獎名單:
  1. 將 unit06-1-1.php 另存新檔為 unit06-1-2.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案的內容 寫入 unit06-1-2.php 當中,並查閱一下網頁的內容
  3. 建立 gogo() 函數的流程:
    • 取得 mod2 這個 ID 的元素控制權
    • 取得 num 這個 ID 的數據 (必須是整數!)
    • 進入判斷 num 數值的防呆,包括 (1)是否為數值? (2)是否在 1 到 myarray.length 之間的數值?
    • 先宣告 i, j, check, got 等變數,其中 i, j 用於迴圈, check 用於判斷有沒有重複的名單,假設 check = 0 代表有重複名單, check == 1 代表沒有重複名單。至於 got 則用於抽籤用,
    • 設定外層的 for 迴圈, i 由 0 到小於 num 的數值,且
      • 假設 check = 0,亦即預設值為有重複的情境
      • 進入 while 迴圈,控制條件為 check == 0 的時候會進行迴圈,內容為
        • 先以 got = Math.floor(Math.random()*myarray.length) 去抓一個索引數值
        • 判斷 i 值,若 i 值為 0 的話,代表第一次處理,則直接設定 check == 1 沒有重複名單
        • 若 i 值不為 0 代表已經有抽獎過,請進入第二層 for 迴圈, j 為 0 到 i 之間的數值,且
          • 先假設沒有重複名單 (check...)
          • 如果 got 與 myget[j] 相同,則 check = 0,且跳出此迴圈,回到上層 while 迴圈,讓其自動再次亂數抽獎
      • 結束 while 迴圈就會有個 got 數值,指定 myget[i] = got 設定。
    • 使用 myget.forEatch 的功能,透過 myarray[gogo] 之類的方式,將名單丟上來系統上
    • 將 mod2.innerHTML 的內容修改成為 msg 喔!
不重複名單的情境

上面這一題是很常見的功能,大家可以理解思考一下。

6.2: 透過文字的解析帶入陣列

6-1-2.php 的例題當中,使用者的相關資料是原本就存在啊,那如果我們想要自己輸入使用者名稱呢?還得要改程式耶! 能不能透過互動的方法來處理?其實也是可以的,透過 textarea 這種大範圍的大方塊,讓使用者把抓到的資料丟進去, 然後透過拆解文字來處理即可。常見的拆解文字可以透過分隔字元來處理。

舉例來說,你可能聽過 csv 這種副檔名的檔案,他的內容是以逗號 (,) 隔開所有的資料,因此,如果你想要將這種資料抓取成為陣列, 可以使用這樣的作法:

var myinput = document.getElementById('someone').value.trim();
var myexp = myinput.split(",");

這樣就輕鬆搞定!你要注意的是:

  • myvar.trim():代表將 myvar 變數的頭尾,如果是空白的話,就予以去除的意思
  • myvar.split(char):代表箱 myvar 的內容以分隔符號 (char) 切開,輸出的資訊會成為陣列。 char 可以是逗號 (,) 也可以是斷行 (\n) 也可以是 [tab] 按鍵 (\t) 等等。

現在,就讓我們使用上面的動作,來測試一下,匯入使用者的訊息資料吧!

例題 6-2-1:讓使用者匯入名單來處理陣列的動作
  1. 建立新檔 unit06-2-1.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案的內容 寫入 unit06-1-1.php 當中,並查閱一下網頁的內容
  3. 撰寫 gogo() 函數,大致的內容大概是:
    • 取得 myform 這個元素的控制權
    • 設定變數,假設 myinput 這個變數為 myform.users.value.trim() 的內容 (去掉頭尾的空白)
    • 設定 users 變數,內容為 mypint.split('\n')
    • 嘗試使用 users.forEach 的功能,將名單列出到 res 這個元素上面。
印出陣列的內容

上面這個動作也是很有趣,透過這個簡單的機制,你應該就可以順利的將名單從 excel 或者是其他任何地方抓下來,然後丟給上面這題, 名單還可以線上修改,可以方便大家抽籤啊!趕緊看一下課後練習第一題來玩一玩。

6.3: 陣列與表單交互應用

有時候,我們可能需要根據使用者的設定,去找出單選或複選的項目,甚至於需要設計清單或表格,來讓資料以列表的方式呈現, 讓使用者具有挑選的功能,最常見的可能就是所謂的單選複選功能吧!

  • 設計單選、複選表單功能

以複選功能為例,大致上的表單設計方式如下:

<input type='checkboxk' name='myvar' value='content1' />content1

因為 myvar 是固定的,他可以是陣列的方式來呈現,因此,如果將 content1 的內容以陣列的值來取代,就可以連續設計出可複選的表單了! 相當簡單!

例題 6-3-1:以陣列的值來處理表單的生成
  1. 建立新檔 unit06-3-1.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案的內容 寫入 unit06-3-1.php 當中,並查閱一下網頁的內容
  3. 撰寫 gogo() 函數,大致的內容大概是:
    • 設定宣告空字串的變數名稱為 msg
    • 使用 Arrayname.forEach 的功能,將每個陣列的數值輸出,輸出的結果類似這樣:
      <label><input type="checkbox" name="myfood[]" value="陣列值" />陣列值</label>
      
    • 取得 myform 這個元素的控制權
    • 將上述的結果回傳給 myform.res.innerHTML 即可!
使用複選的表單設計

未來如果你有任何想要丟進去處理的食堂,直接加在程式碼裡面就好!不用重複處理相關的事情了!方便得很!

  • 複選表單的全選、全不選功能

不過,我們還是有個困擾,那就是,如果需要全選的時候該如何設計?其實這個也不難,你可以指定一個 checkbox 在表單當中, 當該表單的 .checked 為 true 時,那就將所有的陣列取得的 checked 全部設定為 true, 而當為 false 時,就全設定為 false 即可!很容易的!

例題 6-3-2:全選與全不選的 checkbox 按鈕
  1. 將 unit06-3-1.php 另存新檔為 unit06-3-2.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 在 form 裡面增加一行新的複選表單,內容大致上有點像這樣:
    <li><label><input type="checkbox" id="myok" onclick='myselect()' />全選/全不選</label><br />
    
  3. 撰寫 myselect() 函數,大致的內容大概是:
    • 設定 myok 變數,內容為取得 myok.checked 的布林值
    • 設定 myfood 變數,內容為透過 name 來取得 myfood[] (對!注意,有中括號存在) 這個元素值
    • 設定一個名為 ans 的變數,這個變數依據 myok 來處理,若 myok 為 true 則 ans 為 true,否則 ans 為 false 布林值。
    • 使用 for 迴圈,讓每個 myfood 的 .checked 都與 ans 同步。
使用複選的表單設計

接下來,開始試試好手氣,如果不知道要吃什麼,就交給電腦亂數來處理吧...去看第二題

6.4: 撲克牌樣板與洗牌功能

接下來,讓我們來玩一下 javascript 的陣列用途,假設目前有撲克牌一付共 52 張 (所以陣列長度為 52 喔!), 假設撲克牌從第 0 號到第 51 號黑桃 1~13、紅心 1~13、磚塊 1~13、桃花 1~13 這樣的編號,而各種花色可以使用底下的代碼來表示:

  • 黑桃: &spades; ♠
  • 紅心: &hearts; ♥
  • 磚塊: &diams; ♦
  • 桃花: &clubs; ♣
  • 產生撲克牌

依據上面的說明,讓我們使用兩層迴圈來達成 52 張牌的列出:

例題 6-4-1:雙層迴圈搭配陣列來列出撲克牌牌面
  1. 建立新檔 unit06-4-1.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 在 body 內容新增資料『 <div id='res'></div> 』
  3. 建立名為 gogo() 的函數,內容有點像這樣:
    • 宣告 poker 為空陣列
    • 使用 for 迴圈,其中 i 為 0 到 3 之間的整數,然後
      • 如果 i 為 0 ,則 poker1 = 黑桃代碼
      • 類推 i 為 1 則為紅心、 2 為磚塊、 3 為桃花
      • 使用 for 迴圈,其中 j 為 0 到 12,然後進行
        • poker 的索引為 k ,因此 k 為 i*13+j 這樣的計算方式 (就可以得到 0~51 喔!)
        • poker[k] = poker1 + ' ' + (j+1) 這樣來結合花樣與數值
    • 使用 poker.forEach 將 poker 的牌面以清單的方式來展示囉!
  4. 最終載入此網頁,即可看到牌面的展示即可。
撲克牌展示的結果 也可以加上一點點 UI 的展示結果: 撲克牌展示的結果
  • 撲克牌洗牌功能

現在你已經知道,這份撲克牌其實很笨,他的展示,就是由 poker[0] ~ poker[51] 固定的牌面展示而已。那麼,如何產生洗牌的效果? 其實也很簡單,使用另外一個陣列,例如 mypoker 這個變數成為陣列,這個陣列裡面由亂數產生器,產生 0~51 的數值,然後將這些數值分別帶入陣列裡面, 因此,陣列的內容就是 0~51 的亂排!等到排列結束,那就是洗牌完成了。那假設 mypoker[0] 的數值為 8 時,就帶入 poker[8] 的牌面, 亦即第一張牌展示就是 poker[8] 的意思!總結來說,就是『 poker[mypoker[0]] 』這樣的概念。

例題 6-4-2:撲克牌的洗牌效果
  1. 將 unit06-4-1.php 另存新檔為 unit06-4-2.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 在 gogo() 的函數內部,在 poker.forEach 之前插入一段洗牌的過程:
    • 宣告 i, j, check 為變數 (不用給值)
    • 宣告 mypoker 為空陣列
    • 進入 for 迴圈,且 i 值為 0~51 之間,在內進行:
      • 指定 check = 0;
      • 進入 while 迴圈,主要是在洗牌,條件式當 check == 0 時,就持續跑迴圈之意
        • 指定變數 rand0 為抽牌順序,內容為: Math.floor(Math.random()*52)
        • 若第一次洗牌,則不用看牌有沒有/重複,亦即當 i 為 0 時,立刻跳出 while 迴圈 (break)
        • 先指定 check = 1
        • 進入 for 迴圈,來比較這個 rand0 有沒有出現過。 j 值為 0 到 i-1 之間
          • 如果 rand0 有等於任何的 mypoker[j] 的話,則指定 check = 0 且跳出 for 迴圈
      • 跳出 while 迴圈後,指定 mypoker[i] 的內容為 rand0 喔!
    • 使用 mypoker.forEach 將 poker 的牌面以清單的方式來展示囉!內容應該要展示 poker[] 才對喔!
  3. 最終載入此網頁,即可看到牌面的展示即可。
撲克牌展示的結果
  • 摸牌小遊戲

如果連洗牌都辦的到了,那麼,將排面蓋住,然後用滑鼠點擊該牌面再將該紙牌翻開的小遊戲,應該也就不難處理了。 你可以這樣想,洗牌洗到的位置,帶入一個號碼,這個號碼就是 mypoker 的索引號碼,透過該索引號碼, 取得了 mypoker[index] 的數值結果,再將該結果帶給 poker[] ,即可取得正確的牌面資訊。唯一要注意的是, 因為我們的 mypoker 與 poker 陣列都是在函數內宣告的,因此該陣列將成為區域變數而無法被其他函數所引用。 因此,我們必須:

  • 先在函數外面預先宣告全域變數的 poker 與 mypoker 這兩個空陣列
  • 在函數內,『千萬不要重複宣告』該陣列即可。
例題 6-4-3:撲克牌翻牌小遊戲
  1. 將 unit06-4-2.php 另存新檔為 unit06-4-3.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 在 gogo() 函數之前,預先宣告 poker 與 mypoker 這兩個變數為空的陣列格式;
  3. 在 gogo() 的函數內部,進行底下的改變:
    • 將 poker 與 mypoker 變數的宣告取消!很重要喔!
    • 在 mypoker.forEach 的輸出中,將輸出的結果取代為類似如下的內容:
      msg = msg + '<li name="page" onclick="mypo(' + i + ')">&nbsp;&nbsp;&nbsp;&nbsp;</li>';
      
      // 上面的結果會產生類似如下的輸出樣式:
      <li name="page" onclick="mypo(20)">    </li>
      
      這串文字將會產生可以被點擊的空白牌面喔!
  4. 設計名為 mygo(i) 的函數內容:
    • 取得 page 的元素控制權,請注意,務必使用 get elements by name 來取得該元素喔!
    • 讓 index0 為 mypoker[i] 的內容
    • 將 poker[index0] 輸出到 page[i] 裡面去
  5. 最終載入此網頁,會看到 52 張空白牌面,可以按下任何一個牌面,即可翻牌
撲克牌展示的結果

6.5: 課後作業

  • 第一題:製作真實名單抽籤行為

將本章節的第 6-2-1 題目與 6-1-2 題目結合,讓你的抽籤行為,可以列出真實的學生名單。 至於學生名單,可以前往各學校的系統查詢喔。另外,因為名單會持續在不同的函數間應用,需要使用到全域變數的設定行為!

匯入名單的抽籤行為
  • 第二題:結合複選表單的功能,繼續來抽籤

將本章 6-3-2 的結果取下來,在底下新增一個按鈕,讓使用者按下按鈕之後,會自動的計算出三個建議去的小店家, 提供使用者一個選擇的機會啊~比較需要注意的,大概就是,你可能需要透過類似:

for ( i=0; i<myfood.length; i++ ) {
    if ( myfood[i].checked == true ) {
        somearray.push(myfood[i].value);
    }
}

之類的方法來產生有勾選的餐廳的陣列。當然,不只這個方法,你也可以透過分析出亂數後,在透過亂數去確認該餐廳有沒有被勾選? 若有勾選就進入推薦名單,沒有的話,就重複抽籤這樣。方法很多,只要能達成目標,就是好方法!當然,最終的目的, 也要讓達成目標的速度越快越好!同時,加上一些界面的配置設計,讓使用者容易看整體畫面,會更好!

複選的抽籤行為
  • 第三題:製作真實名單後,持續以複選表單來抽籤的行為

結合上面兩題,讓你的真實名單在抽籤時,也可以透過複選的勾選功能 (且,要求預設全部都勾選),讓抽籤主持人可以依據是否人在現場, 給予抽籤的取消與否!那就不用在方塊裡面抽換名單,而是可以透過直接勾選的功能來處理!

真實名單的複選的抽籤行為 真實名單的複選的抽籤行為 真實名單的複選的抽籤行為