2019年12月10日 星期二

以仿 jQuery 的自訂函數簡化網頁 DOM 元件之存取

前端網頁設計師必學的 jQuery 是 DOM 操作的瑞士刀, 它的 $() 函數使繁雜的 DOM 操作變簡單, 若元素的 id 屬性值為 myid, 則用 $("#myid") 即可取得 此元素之 jQuery 物件, 呼叫 jQuery 物件的方法即可對該元素進行取得 (沒傳參數為 getter) 或設定 (有傳參數為 setter) 操作, 例如 :

var obj=$("#myid");
var value=obj.val();            //取得元素的值 (value 屬性之值)
obj.val("200");                    //設定元素之值 (value 屬性之值)
var html=obj.html();           //取得元素之內容 (innerHTML)
obj.html("Hello World");    //設定元素之內容 (innerHTML)
var css=obj.css();                //取得元素之樣式
obj.css("width","200px");   //設定 CSS 樣式

$ 運算符真的讓程式碼變得更簡潔了, 如果用傳統的方式直接操作 DOM 的話, 可用元素的 id, name, class 屬性或元素本身的 tag 來存取, 這樣就得用又臭又長的 document.getElementByXXXX() 來取得 HTML 元素, 最常用的是 id, 例如 :

var obj=document.getElementById("myid");
var value=obj.value;                     //取得 getter
obj.value=200;                              //設定 setter
var html=obj.innerHTML;            //取得 getter
obj.innerHTML="Hello World";  //設定 setter

其實如果原本就已熟悉 DOM 操作, 又沒時間學 jQuery 的話, 可以模仿 jQuery 自訂幾個函數來簡化 DOM 的存取, 例如可自訂 $i() 函數來取得指定 id 的 DOM 元素, 方法很簡單, 就是利用 return 傳回取得之 DOM 物件即可 :

function $i(id) {return document.getElementById(id);}
function $n(name) {return document.getElementsByName(name);}
function $c(classname) {return document.getElementsByClassName(classname);}
function $t(tagname) {return document.getElementsByTagName(tagname);}

上面四個函數 $i(), $n(), $c(), 與 $t() 刻意加了一個字元以避免與 jQuery 衝突, 與 jQuery 一起使用也沒問題, 但差別是 jQuery 的 $() 傳回的是 jQuery 物件, 而上面四個函數傳回的是 DOM 物件.

$i() 傳入 id 字串即可取得 DOM 物件, id 理論上在網頁中必須是唯一的, 因此它是單數的 getElement; 其他三個方式都可能取回多個物件, 其傳回值是一個集合 (也就是陣列), 故它是複數的 getElements :
  • $i() 傳入 id 取得相同 id 屬性之物件
  • $n() 傳入 name 取得相同 name 屬性之物件集合 
  • $c() 傳入 class 樣式名稱取得相同 class 屬性之物件集合 
  • $t() 傳入 tag 名稱取得相同標籤之物件集合  
注意, 物件集合要用陣列索引 [] 的方式存取元素, 或使用迴圈逐一拜訪來存取個別元素 (例如選項圓鈕就是多個選項共用同一名稱). 例如下面範例中, name, class, 以及 tag 為 "input" 的元素只有一個, 故用 [0] 存取物件集合中的第一個元素即取得此 input 元素 :


範例 1 : DOM 元素存取簡化函數測試 [看原始碼]

<!DOCTYPE html>
<html>
<head>
  <title>DOM $ functions</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
  <input type="text" id="input" name="input" class="input" value=""><br>
  <button onclick="byid(this)">getElementById</button><br>
  <button onclick="byname(this)">getElementsByName</button><br>
  <button onclick="byclass(this)">getElementsByClassName</button><br>
  <button onclick="bytag(this)">getElementsByTagName</button>
  <script>
    function $i(id) {return document.getElementById(id);}
    function $n(name) {return document.getElementsByName(name);}
    function $c(classname) {return document.getElementsByClassName(classname);}
    function $t(tagname) {return document.getElementsByTagName(tagname);}
    function byid(obj) {
      $i("input").value=obj.innerHTML;
      }
    function byname(obj) {
      $n("input")[0].value=obj.innerHTML;
      }
    function byclass(obj) {
      $c("input")[0].value=obj.innerHTML;
      }
    function bytag(obj) {
      $t("input")[0].value=obj.innerHTML;
      }
  </script>
</body>
</html>

此例藍色部分的函數就是模仿 jQuery 製作的 DOM 元素存取函數, 每一個按鈕的 onclick 事件都傳入 this 表示按鈕元素本身, 然後即可利用 value, innerHTML 等 DOM 原始屬性來操控網頁元素了, 瀏覽結果如下 :




按下按鈕時利用 innerHTML 取得 button 元素之內容, 然後設定給 input 輸入欄位之 value 屬性, 這樣文字框就會顯示按鈕上的文字了. 除了文字欄位外, 其他常用的表單元件有 radio, checkbox, 以及 select, 參考 :

# 網頁技術速學筆記 (四) : HTML 表單

下面範例利用 $n() 來測試單選圓鈕選項的操控 :


範例 2 : 用 $n() 元素存取單選圓鈕選項 [看原始碼]

<!DOCTYPE html>
<html>
<head>
  <title>DOM $ functions</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
  <p>最好看的戲劇:</p>
  <input type="radio" name="drama" value="The K2">The K2<br>
  <input type="radio" name="drama" value="很便宜,千里馬超市">很便宜,千里馬超市<br>
  <input type="radio" name="drama" value="不經意發現的一天">不經意發現的一天<br>
  <input type="radio" name="drama" value="熟男還不結婚">熟男還不結婚<br><br>
  <button onclick="ok()">確定</button>
  <script>
    function $i(id) {return document.getElementById(id);}
    function $n(name) {return document.getElementsByName(name);}
    function $c(classname) {return document.getElementsByClassName(classname);}
    function $t(tagname) {return document.getElementsByTagName(tagname);}
    function ok() {
      var objs=$n("drama");    //傳回 input 元素物件陣列
      if (objs.length == undefined) {   //只有一個選項時 length 為 undefined
        alert("只有一個選項!");
        }
      else {
        var item=""; //儲存所選擇之選項值
        for (var i=0; i<objs.length; i++) {
          if (objs[i].checked) {item=objs[i].value;}
          }
        alert(item);
        }
      }
  </script>
</body>
</html>

此例中呼叫 $n() 傳回名稱為 drama 的 input 元素陣列, 若 radio 只有一個選項, 則陣列長度 length 為 undefined, 因此必須先判別處理, 否則進入迴圈會出現錯誤, 結果如下 :




下面是核取方塊 (複選) 的範例 :


範例 3 : 用 $n() 元素存取核取方塊選項 [看原始碼]

<!DOCTYPE html>
<html>
<head>
  <title>DOM $ functions</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
  <p>已看過的戲劇:</p>
  <input type="checkbox" name="drama" value="The K2">The K2<br>
  <input type="checkbox" name="drama" value="很便宜,千里馬超市">很便宜,千里馬超市<br>
  <input type="checkbox" name="drama" value="不經意發現的一天">不經意發現的一天<br>
  <input type="checkbox" name="drama" value="熟男還不結婚">熟男還不結婚<br><br>
  <button onclick="ok()">確定</button>
  <script>
    function $i(id) {return document.getElementById(id);}
    function $n(name) {return document.getElementsByName(name);}
    function $c(classname) {return document.getElementsByClassName(classname);}
    function $t(tagname) {return document.getElementsByTagName(tagname);}
    function ok() {
      var objs=$n("drama");
      if (objs.length == undefined) {var length=1;}
      else {var length=objs.length;}
      var items=[]; //儲存所選擇之選項值
      for (var i=0; i<objs.length; i++) {
        if (objs[i].checked) {items.push(objs[i].value);}
        }
      alert(items.join("-"));
      }
  </script>
</body>
</html>

因為 checkbox 是複選, 故此例使用陣列 items 來儲存被選取之項目值, 最後呼叫 join() 用 dash 來串接陣列元素為字串, 結果如下 :




下面是單選的下拉式選單範例 :


範例 4 : 用 $n() 元素存取下拉式選單選項 [看原始碼]

<!DOCTYPE html>
<html>
<head>
  <title>DOM $ functions</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
  <p>最好看的戲劇:</p>
  <select name="drama">
    <option value="The K2">The K2
    <option value="很便宜,千里馬超市">很便宜,千里馬超市
    <option value="不經意發現的一天">不經意發現的一天
    <option value="熟男還不結婚">熟男還不結婚
  </select>
  <br><br>
  <button onclick="ok()">確定</button>
  <script>
    function $i(id) {return document.getElementById(id);}
    function $n(name) {return document.getElementsByName(name);}
    function $c(classname) {return document.getElementsByClassName(classname);}
    function $t(tagname) {return document.getElementsByTagName(tagname);}
    function ok() {
      var objs=$n("drama");
      alert(objs[0].value);
      }
  </script>
</body>
</html>

此例雖然有許多選項, 但因為主體是 select, 其值就是被選取之選項, 故不需用到迴圈. 因為使用 $n() 函數, 其傳回值為陣列, 故需用 [] 來取得 select 元素, 如果用 $i() 就不需要. 結果如下 :




下拉式選單為單選, 多選的 select 要加 multitple 屬性, 最好再加上 size 屬性顯示全部屬性, 這種 select 元件稱為清單 (list), 其操作與 checkbox 類似, 但用 selected 而非 checked 檢查被選取之項目, 例如 :


範例 5 : 用 $n() 元素存取清單選項 [看原始碼]

<!DOCTYPE html>
<html>
<head>
  <title>DOM $ functions</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
  <p>最好看的戲劇:</p>
  <select name="drama" size="4" multiple>
    <option value="The K2">The K2
    <option value="很便宜,千里馬超市">很便宜,千里馬超市
    <option value="不經意發現的一天">不經意發現的一天
    <option value="熟男還不結婚">熟男還不結婚
  </select>
  <br><br>
  <button onclick="ok()">確定</button>
  <script>
    function $i(id) {return document.getElementById(id);}
    function $n(name) {return document.getElementsByName(name);}
    function $c(classname) {return document.getElementsByClassName(classname);}
    function $t(tagname) {return document.getElementsByTagName(tagname);}
    function ok() {
      var obj=$n("drama");
      var opts=obj[0].options;
      var len=opts.length;
      var items=[];
      for (var i=0; i<len; i++) {
        opt=opts[i];
        if (opt.selected) {items.push(opt.value);}
        }
      alert(items.join("-"));
      }
  </script>
</body>
</html>

此例呼叫 $n() 取得 select 元素, 故需用 [0] 存取網頁第一個 select 物件, 其 options 屬性代表 select 裡面的 option 物件群, 其 length 屬性表示共有幾個選項, 利用此 length 拜訪 option 物件集合, 並以 selected 判斷有無被選取, 有的話就將 value 放入陣列, 結果如下 :




注意, 清單的 size 最好與選項數目一樣, 這樣全部選項才會一次展開, 這樣要複選較好操作.

參考 :

https://pjchender.blogspot.com/2015/11/javascript.html
Document.getElementsByClassName()
https://www.dyn-web.com/tutorials/forms/select/multi-selected.php

沒有留言:

張貼留言