javascript-TreeView父子聯動效果保持節點狀態一致_javascript技巧

來源:互聯網
上載者:User
我們大部分都用過TreeView控制項,對這個控制項的評價也是各式各樣的,但是我覺得不論如何它是一個免費的開源的控制項,所以我還是在用它。在剛接觸ASP.NET的時候,記得需要做一個分配許可權的許可權樹,當時只知道有這個樹,經過一天的研究對其伺服器端的行為基本以及搞清楚了,但是由於當時的js水平有限,所以對用戶端的代碼很畏懼,基本沒有看過。
當時有這樣一個要求:如果一個節點被選中則該節點的所有子節點都要選中,如果該節點的所有子節點取消選擇則該節點也要取消選擇(節點一致性),相反一樣。
還有一個要求就是:如果可以實現三態樹則更好(這個有點難,本文中不予討論)。本文將詳細介紹前面要求1。
        首先我們要慶幸微軟的這個TreeView控制項是開源的,不論是用戶端代碼還是伺服器端代碼您都可以輕鬆獲得,可以去微軟的網站上下載。在網上也見過一些講述該問題的文章,他們大多是使用一個TreeView之外的js實現,我個人認為從物件導向的觀點,該功能屬於TreeView,所以沒有理由將它分離出去,因此今天我將修改TreeView.htc來實現上面的功能。要想獲得該檔案(TreeView.htc)可以去微軟的網站上下載之。
說實在的該功能曾經也困擾了我很久,一直想解決這個問題,但是一直沒有時間來研究TreeView.htc中的代碼,今天終於下決心搞定它。
        我們知道在TreeView的oncheck中需要激發該事件處理函數,這個函數很容易找到,可以在TreeView產生的客戶度指令碼中找到,代碼片斷如下:
oncheck="javascript: if (this.clickedNodeIndex != null) this.queueEvent('oncheck', this.clickedNodeIndex)"
        由此我們可以去htc(以後說的htc都指的是TreeView.htc),找到doCheckboxClick方法,只要看名字就知道它是幹什麼的(命名實在太重要了,否則在3000行代碼中找某個函數真的很累)。
        該方法是當使用者點擊CheckBox的使用要處理的函數,函數如下所示:
        function doCheckboxClick(el){
            var checked = private_getAttribute(el,"checked")
            el.checked = !checked;
            var evt = createEventObject();
            evt.treeNodeIndex = getNodeIndex(el);
            g_nodeClicked = el;
            _tvevtCheck.fire(evt);
            setNodeState(el,el.checked);// maybe need el only,but I think it's safly
        }
        其中第一行、第二行以及最後一行是我添加的,第一二行是為了在頁面回傳以後checked屬性無效時所做的修改,按照原來的方法在提交後el.checked是undefined,所以導致無法正確同步節點,如果讀者有興趣可以試一試。setNodeState函數,從名字上可以看出該函數是用來設定節點狀態的,它將當前你選擇的節點作為參數傳遞到函數內部。如注釋中所說實際上你可以只傳遞el進去,而無需再傳一個布爾值,不過我想這樣傳遞可能更安全,不過沒有關係,你覺得不爽可以修改:。
        下面看看setNodeState的函數體,該函數由兩個方法組成,一個是設定所有孩子節點的狀態,一個是設定該節點的父節點狀態。代碼如下:
        function  setNodeState(el,state){
            _setChildNode(el,state);
            _setParentNode(el,state);
        }
        為了可以設定當前節點的所有孩子節點是否和父節點(本節點)狀態一至我們需要函數_setChildNode,同理為了使節點的父節點和該節點狀態一至我們需要_setParentNode函數。兩個函數都是遞迴函式,將會遍曆所有的子節點和所有的父節點以及兄弟節點(為什麼要遍曆兄弟節點稍候再說),下面我們先看看遍曆孩子節點的代碼,代碼如下所示:
        function  _setChildNode(el,state){
            var childNodes = el.children;
            if(childNodes.length > 0){// if has childs 
                for(var i = 0 ;i<=childNodes.length-1;i++){
                    private_setAttribute(childNodes[i],"Checked",state);
                    _saveCheckState(childNodes[i]);
                    _setChildNode(childNodes[i],state);
                }
            }
        }
        該函數先獲得當前節點的所有子節點,這裡可以直接使用TreeView提供的函數getChildren方法,而我使用的使html的原始方法。如果該節點存在子節點則遍曆所有子節點,同時設定子節點的狀態和當前節點的狀態一致,_saveCheckState函數的作用稍候會介紹。private_setAttribute方法為TreeView提供的一個內部設定屬性的方法(js沒有private關鍵字,這裡只是做說明而已),該方法將設定每一個節點的Checked屬性為當前這個節點的狀態。
        下面是如何設定父節點狀態的代碼:
         function  _setParentNode(el,state){
            var parentNode = el.parentElement;
            if(parentNode){
                if(!_checkSiblingdNode(el)){
                    private_setAttribute(parentNode,"Checked",state);
                    _saveCheckState(parentNode);
                    _setParentNode(parentNode,state);
                }
            }
        }
        該函數先獲得其父節點,如果父節點存在則檢查當前節點的兄弟節點,上面有提到了需要檢查兄弟節點,這裡檢查兄弟節點的目的是:父節點的狀態不是由當前節點一個節點控制的(這種情況只存在於當前節點沒有兄弟節點的情況下),如果有其他兄弟是選中的,那麼父節點是不能被取消了,這樣將導致兄弟節點和父子節點不一致不一致。該函數裡面也調用了_saveCheckState函數,在後面將介紹之。
下面的代碼描述了如何檢查兄弟節點的狀態,代碼如下:
        function _checkSiblingdNode(el){
            var parentNode = el.parentElement;// you can use getParentTreeNode function in this htc,but I like this usage.
            for(var i = 0;i<=parentNode.children.length-1;i++){
                if(el != parentNode.children[i]){
                    if(private_getAttribute(parentNode.children[i],"Checked")){
                        return true;
                    }
                }
            }
            return false;
        }
        正如注釋所述,你可以使用getParentTreeNode方法來獲得節點的父節點,但是我比較喜歡使用原始的方法:。這裡將排除自己(if(el!=parentNode.children[i]))。
        有了上面的代碼我們就可以做到用戶端無重新整理的父子節點一致的選擇,那麼我們現在來介紹一下_saveCheckState函數,如果沒有該函數頁面提交以後,剛才除了手工點擊的節點以外其他的節點都不能儲存狀態。所以該函數的作用就是要儲存所有節點的狀態(主要是自動選擇的節點),保證在回傳之後樹的狀態依然存在。下面的代碼描述了_saveCheckState函數,代碼如下:
        function _saveCheckState(el){
            if(getNodeIndex(el))
                queueEvent('oncheck', getNodeIndex(el));
        }
        該方法首先檢查當前節點的index是否有效,如果有效則儲存狀態。這裡需要說一下queueEvent方法做了什麼,代碼我就不帖了,該函數的實際意義是將用戶端的操作儲存在一個名為__TreeView1_State__的隱藏欄位中,這樣在回傳的時候伺服器端會根據該隱藏欄位,初始化樹的狀態。其中TreeView1是我在測試系統中TreeView的名字。
        最後的問題就是部署的問題了,因為修改了htc,所以在部署的時候需要替換原來的htc檔案。
        如果有需要修改之後的TreeView.htc(格式化之後的),可以在CSDN上改我留言留下email。我的CSDN帳號是cuike519。
        希望微軟可以早日將這個功能添加到TreeView控制項中,最好也能實現多態的樹結構。請瀏覽blog的相關評論,我會在評論中更新文章!
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.