而輔助這些互動功能的語法均需要使用 CSS 及 Javascript
在 Javascript 方面,由於得到 jQuery 的跨瀏覽器語法,在開發 Javascript 新功能時可以不再考慮瀏覽器的問題
可能不少網頁設計者都會遇過類似狀況
輸入文字欄位數量不夠,需要新加入一定數量的輸入文字爛位,但究竟多少才足夠卻不是設計師可以控制
最理想的狀況是由使用者在需要增加資料,增加輸入文字爛位
<table> <tbody> <tr> <td><input type="text"/></td> <td><input type="button" value="+"/></td> <td><input type="button" value="-"/></td> <td><input type="button" value="▼+"/></td> <td><input type="button" value="▲"/></td> <td><input type="button" value="▼"/></td> </tr> </tbody> </table>以上的 HTML 會以下面的方式顯示
當 - 被按下後,選定的列會被移除
當 ▼+ 被按下後,複製選定的列於下一列
當 ▲ 被按下後,選定的列向上移
當 ▼ 被按下後,選定的列向下移
網上有不少使用 jQuery 的教學達成這種操作
而這裡則是使用 DOM 的方式達成這種操作
先利用 Javascript 的 Prototype 補充原來的 Javascript 的不足之處
Prototype Javascript
// DOM 的 Node 有 nextSibling 及 previousSibling 屬性
// 來獲取 Node 的上一個 Node 及 下一個 Node ,當沒有 Node 時,會得到 null
// 但 *Sibling 可能比較難記,可以自行增加 nextNode() 及 previousNode() 功能
// (Java 來說會以功能操作比較熟習)
Node.prototype.nextNode = function(){
return this.nextSibling;
}
Node.prototype.previousNode = function(){
return this.previousSibling;
}
// 但上一個 Node 或下一個 Node 不一定是 Tag
// 對於 DOM Tag 與 Tag 之間的空白字元都是 Node 只是 nodeType 的不同
// Tag 的 nodeType 為 1
Node.prototype.nextTag = function(){
var node = this.nextNode();
while (node != null && node.nodeType != 1){
node = node.nextNode();
}
return node;
}
Node.prototype.previousTag = function(){
var node = this.previousNode();
while (node != null && node.nodeType != 1){
node = node.previousNode();
}
return node;
}
// 獲取第一及最後的 Tag
Node.prototype.firstTag = function(){
var node = this.firstChild;
while (node != null && node.nodeType != 1){
node = node.nextNode();
}
return node;
}
Node.prototype.lastTag = function(){
var node = this.lastChild;
while (node != null && node.nodeType != 1){
node = node.previousNode();
}
return node;
}
// DOM 的 Node 只有 insertBefore 功能卻沒有 insertAfter 功能
// 可以自行編寫 insertAfter 來補足功能
Node.prototype.insertAfter = function(new_node, existing_node){
if (new_node instanceof Node){
existing_node.parentNode.insertBefore(new_node, existing_node.nextNode());
}
}
// 讓兩個 DOM Node 的位置交換
Node.prototype.swap = function(node){
if (node instanceof Node){
var parent = this.parentNode;
parent.insertBefore(node.cloneNode(true), this);
parent.insertBefore(this.cloneNode(true), node);
parent.removeChild(this);
parent.removeChild(node);
}
}
// 自編 insertRowBefore 及 insertRowAfter 功能
// 將新的 列 新增至 當前列 的 前 或 後
HTMLTableRowElement.prototype.insertRowBefore = function(row){
if (row instanceof HTMLTableRowElement){
this.parentNode.insertBefore(row, this);
}
}
HTMLTableRowElement.prototype.insertRowAfter = function(row){
if (row instanceof HTMLTableRowElement){
this.parentNode.insertAfter(row, this);
}
}Javascript
function add_row(input){
var td = input.parentNode;
var tr = td.parentNode;
var tx = tr.parentNode;
var t_tr = tx.rows[0].cloneNode(true);
t_tr.removeAttribute('style');
tr.insertRowAfter(t_tr);
}
function copy_row_input_value(tr1, tr2){
for (var i = 0; i < tr1.cells.length; i++){
var element = tr1.cells[i].firstChild;
if (element instanceof HTMLInputElement){
if (element.type == 'radio' || element.type == 'checkbox'){
tr2.cells[i].firstChild.checked = element.checked;
} else {
tr2.cells[i].firstChild.value = element.value;
}
} else if (element instanceof HTMLSelectElement){
tr2.cells[i].firstChild.selectedIndex = element.selectedIndex;
} else if (element instanceof HTMLTextAreaElement){
tr2.cells[i].firstChild.innerHTML = element.innerHTML;
}
}
}
function copy_row(input){
var td = input.parentNode;
var tr = td.parentNode;
var tx = tr.parentNode;
var t_tr = tx.rows[0].cloneNode(true);
t_tr.removeAttribute('style');
tr.insertRowAfter(t_tr);
copy_row_input_value(tr, t_tr);
}
function delete_row(input){
var td = input.parentNode;
var tr = td.parentNode;
var tx = tr.parentNode;
if (tx.rows.length <= 2){
add_row(input);
}
tx.removeChild(tr);
}
function move(input, direction){
var td = input.parentNode;
var tr = td.parentNode;
var tx = tr.parentNode;
var t_tr = tr.cloneNode(true);
copy_row_input_value(tr, t_tr);
if (tr != tx.firstTag().nextTag() && direction == 'up'){
tx.insertBefore(t_tr, tr.previousTag());
tx.removeChild(tr);
} else if (tr != tx.lastTag() && direction == 'down'){
tx.insertAfter(t_tr, tr.nextTag());
tx.removeChild(tr);
}
}
function move_up(input){
move(input, 'up');
}
function move_down(input){
move(input, 'down');
}
HTML
<table> <tbody> <tr style="display: none;"> <td><input type="text"/></td> <td><input type="button" value="+" onclick="add_row(this);"/></td> <td><input type="button" value="-" onclick="delete_row(this);"/></td> <td><input type="button" value="▼+" onclick="copy_row(this);"/></td> <td><input type="button" value="▲" onclick="move_down(this);"/></td> <td><input type="button" value="▼" onclick="move_up(this);"/></td> </tr> <tr> <td><input type="text"/></td> <td><input type="button" value="+" onclick="add_row(this);"/></td> <td><input type="button" value="-" onclick="delete_row(this);"/></td> <td><input type="button" value="▼+" onclick="copy_row(this);"/></td> <td><input type="button" value="▲" onclick="move_down(this);"/></td> <td><input type="button" value="▼" onclick="move_up(this);"/></td> </tr> </tbody> </table>由於第一列使用 display: none 來隱藏列,因此複製的列需要移除 style 屬性
另外由於 input, select, textarea 等 表單元素 不會複製由用戶輸入的 value, checked, selected, innerHTML 等資料
複製列時需要連同 value, checked, selected, innerHTML 等資料一拼複製才能達至複製效果
以下是示範
這種方法的可取之處是不需要使用 id, class 之類的 CSS Selector 達到效果
沒有留言 :
張貼留言