今天讨論一下TreeView控件的互動問題。包括滑鼠對TreeNode的選取(單選&多選)、Checked;鍵盤對TreeNode的選取(單選&多選)、Checked;通過代碼和控件互動三種方式。最後提供一個現階段完成版本的示範示例供大家測試。

<script language="javascript">
</script>
當然,為了能靈活的使用滑鼠和TreeViee互動,我們需要處理大部分的滑鼠事件。包括click、mousedown、mouseover、mouseout和mousemove。同時在處理這些滑鼠事件時,很多時候還需要和鍵盤配合來操作,比如:Shift+Click的區段選取,Ctrl+Click的check方式選取等。
在TreeNode的Render方法中,處理節點展開和收縮的事件是比較簡單的,因為那隻是一個開/關狀态的轉換。在TreeNode上做Check操作時需要注意,為了讓控件的腳本類(TreeNode的執行個體)和DHTML類之間屬性值同步,我們需要完全控制Checkbox的狀态的變化,并且為了避免後面我們使用鍵盤來Check節點時出錯,我們還必須保證Checkbox始終不能獲得焦點。
input.onfocus = function(){ FindParentElement(this, 'TD').focus(); };
// 總是把焦點置于Checkbox的Parent元素上
由于我們已經實作了一套對UI更新的機制,就是統一使用ApplyUIChange()方法來負責。是以除了mousedown事件外,其它的事件處理函數都非常的簡單,隻需要設定一下控件屬性,然後調用ApplyUIChange()就行了,比如:__CheckBoxOnClick(),它的實作就非常的簡單清晰。
TreeNode.__CheckBoxOnClick = function()
{
var elmtNode = FindParentElement(this, 'TR');
if ( elmtNode && elmtNode.Comment == 'TreeNode' )
{
var objNode = elmtNode.Object;
if ( objNode )
{
objNode.SetChecked(this.checked);
}
}
};
但是由于mousedown事件需要和鍵盤配合,并且本身它自己就承擔着很多的互動功能,是以處理起來比較麻煩。而其中最麻煩的就是按住Shift鍵再Click的區段TreeNode選取功能。
if ( evt.shiftKey && !evt.ctrlKey )
{
if ( innerCache.m_Selecteds.m_Count == 0 )
objNode.SetSelected(true);
innerCache.m_LastSelected = objNode;
}
var startNode = innerCache.m_LastSelected;
var endNode = objNode;
var posStart = GetAbsoluteLocation(startNode.m_Element).absoluteTop;
var posEnd = GetAbsoluteLocation(endNode.m_Element).absoluteTop;
innerCache.UnselectAll();
if ( startNode != endNode )
{
if ( posStart > posEnd )
{
var tmp = startNode;
startNode = endNode;
endNode = tmp;
}
var curNode = startNode;
do
curNode.SetSelected(true);
curNode = curNode.GetNextRowNode();
while(curNode != endNode);
endNode.SetSelected(true);
else
endNode.SetSelected(true);
}
這個功能首先需要判斷,目前事件是不是mousedown并且同時鍵盤Shift被按下了。上面第一個if就是做這個判斷的,當确認了使這個事件條件後,我們需要判斷目前的TreeView上是否存在最近(一種被選中時的循序的狀态)被Selected的節點,這個節點将被用作區段選取的起點,滑鼠mousedown(width shift)的節點将會是區段選取的終點。innerCache.m_Selecteds.m_Count == 0說明沒有起點,那麼我們就置目前被點下的點為起點(這是一個最近點),同時完成本次選取操作。如果在mouse down width shift key的時候,TreeView上有超過一個節點已被Selected,那麼我們就取出起點(最近點)和終點,并開始計算起點和終點的位置關系,誰在上誰在下?然後把這兩個節點整理為起點始終是在上面的節點,終點始終是在下面的節點(在螢幕上的相對位置),這樣是為了使用同樣的代碼就能把兩個方向的Selected工作都做了。然後清除TreeView上所有已選中的節點,從起點開始往終點Selected就行了:
do
curNode.SetSelected(true);
curNode = curNode.GetNextRowNode();
}
while(curNode != endNode);
簡單吧,可是這個curNode.GetNextRowNode()又不是很簡單
,在處理鍵盤事件中我們再來詳細說它。那麼我們在鍵盤上需要處理那些操作呢?看下面的代碼,我們處理:Up、Down、+、-、Space和Esc這幾個按鍵。

上面的代碼,switch前是為了取到被操作的TreeNode對象。+、-、Space和Esc都很簡單,從代碼中一眼就看明白了,麻煩的就是Up和Down這兩個操作。其實在這裡希望實作的操作都是WinControl的TreeView中支援的,隻是被移到Web的控件上而已。Up和Down操作就是Selected最近那個節點的相鄰節點,或上面的或下面的。如果我們在一個層次上來找一個節點的上一個和下一個,那是非常簡單的index-1、index+1就行了,可是在樹這樣的層次結構中,尋找一個它的看起來的上一個或下一個展開的節點,就比較郁悶了。兩個方法:
var previousNode = currentNode.GetPreviousRowNode();
var nextNode = currentNode.GetNextRowNode();
要說明白它們是幹嘛的,都比較難。這麼說吧,當這個TreeView展現我們面前時,我們暫時忽略節點之間的層級關系,把它們的節點看成向List的條目一樣的結構,GetPreviousRowNode(),就是取上一行的Node,GetNextRowNode()就是取目前節點下一行的節點。

弄個圖來配合代碼看可能比較容易了解些
:
嗯,其它的問題先玩玩demo再繼續讨論吧
。
本文轉自部落格園鳥食軒的部落格,原文連結:http://www.cnblogs.com/birdshome/,如需轉載請自行聯系原部落客。