Esse artigo mostrar como criar um TreeView no Javascript , atualmente estou em um projeto web com json, com isso não posso utilizar componentes do asp.net, sendo assim, estou utilizando muito o Javascript. Tive alguns problemas para criar o treeview como posição da imagens e texto, mas no final ficou muito boa a visualização do TreeView.

Testei o TreeView em 3 browsers (IE, Firefox, Chrome) e funcionou sem problemas. Na figura abaixo mostro as classes utilizadas para construir o TreeView.

img

Vamos construir o HTML. No evento onload da tag BODY, vamos chamar a função loadTreeView que vai construir o nosso TreeView.

<html>
<head>
    <title></title>
    <style type="text/css">
                     
    </style>
    <script language="javascript" type="text/javascript">
        
    </script>
</head>
<body onload="loadTreeView(document.getElementById('contentTreeViewDiv'));">
    <div id="contentTreeViewDiv" >
        
    </div>
</body>
</html>

Como disse anteriormente, tive alguns problemas para alinhar imagem e texto no html, como solução coloquei as imagens como background em uma tag LABEL. Nesse momento criaremos os estilos do html.

.fontTree
{
    font-family:Segoe UI, Tahoma, Sans-Serif;
    font-size:10pt;
    color:#1F3870;          
}
        
.nolines_PlusTree
{       
    background: url(Imagens/nolines_plus.gif) no-repeat left;
}
        
.nolines_MinusTree
{       
    background: url(Imagens/nolines_minus.gif) no-repeat left;
}        
        
.joinTree
{       
    background: url(Imagens/join.gif) no-repeat left;
}  
        
.joinBottomTree
{       
    background: url(Imagens/joinbottom.gif) no-repeat left;
}       
                      
.plusBottomTree
{       
    background: url(Imagens/plusbottom.gif) no-repeat left;
}   
        
.plusTree
{       
    background: url(Imagens/plus.gif) no-repeat left;
}     
        
.minusTree
{       
    background: url(Imagens/minus.gif) no-repeat left;
}  
        
.minusBottomTree
{       
    background: url(Imagens/minusbottom.gif) no-repeat left;
}       
        
.lineTree
{       
    background: url(Imagens/line.gif) no-repeat left;
}
img

Vamor criar a classe treeView e seus métodos e propriedades.

//Classe TreeView
function treeView() {
    this.nodeRoot = null;//Tipo itemNode.
}
Classe
//Adiciona um nó raiz.
treeView.prototype.addNodeRoot = function (id, name, image, isExpand, link) {
    this.nodeRoot = new itemNode(id, name, image, isExpand, link);

    return this.nodeRoot;
};

//Limpa o nó raiz.
treeView.prototype.clear = function () {
    this.nodeRoot = null;
};

//Retorna o conteúdo html para criar o treeview.
treeView.prototype.contentHtml = function () {
    return this.nodeRoot.contentHtml(this.nodeRoot.id, 0, true, 
    false, false, this.nodeRoot.isExpand, true);
};  
Métodos

Vamor criar a classe itemNode e seus métodos e propriedades.

//classe Nó.
function itemNode(id, name, image, isExpand, link) {
    this.id = id;//Identificador do nó
    this.name = name; //Texto do nó.
    this.image = image;//Imagem do nó
    this.isExpand = isExpand;//Indica se o nó é mostrado expandido no momento da criação.
    this.link = link;//Indica se o nó vai ser um link.
    this.items = [];//Coleção de nós filhos.
}
Classe
//Adiciona um nó filho
itemNode.prototype.addNode = function (id, name, image, isExpand, link) {
    var obj = new itemNode(id, name, image, isExpand, link);

    this.items[this.items.length] = obj;

    return obj;
};

//Limpa a coleção de nós filhos.
itemNode.prototype.clear = function () {
    this.items = [];
};

//Obtém identificadores dos nós filhos. Utilizado para expandir 
e recolher os nós filhos.
itemNode.prototype.getIdChildNodes = function () {
    var arrayId = '';

    for (var i = 0; i < this.items.length; i++) {
        arrayId += this.items[i].id + ';';
    }

    return arrayId;
}

//Retorna o conteúdo html para criar o treeview.
//<param name="id">Identificador do objeto nó.</param>
//<param name="indent">Identação dos nós.</param>
//<param name="nodeFirst">Indica se o nó é o nó raiz.</param>
//<param name="nodeSingle">Indica se o nó não tem irmãos.</param>
//<param name="isImgLine">Indica se imagem linha será adicionada. 
É adiciona quando o pai do nó tem irmão.</param>
//<param name="isExpand">Indica se o nó vai estar expandido no 
momento da criação.</param>
//<param name="parentNodeSingle">Indica se o pai do nó não tem 
irmãos. Isso indica para a funão adicionar ou não a imagem linha</param>
itemNode.prototype.contentHtml = function (id, indent, nodeFirst, 
nodeSingle, isImgLine, isExpand, parentNodeSingle) {
    var content = '';
    var strIndent = '';

    for (var i = 0; i < indent; i++) {
        strIndent += '   ';
    }

    var className = '';
    var lineImg = '';
    var addImgLine = false;

    if (!nodeFirst && !nodeSingle) {
        addImgLine = true;
    }

    if (nodeFirst) {
        if (!isExpand) {
            className = 'nolines_PlusTree';
        }
        else {
            className = 'nolines_MinusTree';
        }

        nodeFirst = false;
    }
    else {
        if (nodeSingle) {
            if (this.items.length == 0) {
                className = 'joinBottomTree';
            }
            else {
                if (!isExpand) {
                    className = 'plusBottomTree';
                }
                else {
                    className = 'minusBottomTree';
                }
            }
        }
        else {
            if (this.items.length == 0) {
                className = 'joinTree';
            }
            else {
                if (!isExpand) {
                    className = 'plusTree';
                }
                else {
                    className = 'minusTree';
                }
            }
        }
    }

    var eventClick = '';

    if (this.items.length > 0) {
        var arrayId = this.getIdChildNodes();

        eventClick = 'onclick="nodeExpand(document.getElementById(\'' 
        + id + '\'), \'' + arrayId + '\')"';
    }

    content += '<div id="' + id + '" style="display:@visible@;">
    <input id="' + id + 'Hidden" type="hidden" value="' 
    + (isExpand ? '1' : '0') + '" />';

    var valueNode = '';
    var valueLink = '';

    if (this.link != null && this.link != '') {
        valueLink = '<a class="fontTree" href="' + this.link + '">' 
        + this.name + '</a>';
    }
    else {
        valueLink = this.name;
    }
            
    if (this.image != null && this.image != '') {
        valueNode = '<label class="fontTree" style="background: url(' 
        + this.image + ') no-repeat left;">     ' + valueLink + '</label>';
    }
    else {
        valueNode = '<label class="fontTree">' + valueLink 
        + '</label>';
    }

    if (isImgLine) {
        var strIndentLine = '';

        for (var i = 0; i < indent - 1; i++) {
            if (i == indent - 2 && parentNodeSingle) {
                strIndentLine += '   <label>  </label>';
            }
            else {
                strIndentLine += '   <label class="lineTree">  
                </label>';
            }
        }

        content += strIndentLine + '   <label id="' + id 
        + 'ClassNameHidden" class="' + className + '" ' + eventClick 
        + '>     </label>' + valueNode + '<br>';

        addImgLine = true;
    }
    else {
        content += strIndent + '<label id="' + id 
        + 'ClassNameHidden" class="' + className + '" ' 
        + eventClick + '>     </label>' + valueNode + '<br>';
    }

    var newindent = indent + 1;

    for (var i = 0; i < this.items.length; i++) {
        var isNodeSingle = false;
        var strValue = '';

        if (i == this.items.length - 1) {
            isNodeSingle = true;
        }

        strValue = this.items[i].contentHtml(this.items[i].id, 
        newindent, nodeFirst, isNodeSingle, addImgLine, 
        (!isExpand ? false : this.items[i].isExpand), nodeSingle);

        if (isExpand) {
            strValue = strValue.replace('@visible@', 'block');
        }
        else {
            strValue = strValue.replace('@visible@', 'none');
        }

        content += strValue;
    }

    content += '</div>';

    return content;
};
Métodos

Utilizamos recursividade para montar o TreeView, cada nó pode ter filhos e irmãos.

Agora vamos criar a função que vai expandir e recolher os nós. Na função contentHtml verificamos se o nó tem filhos ou não, caso o nó é pai de outros nós adicionamos essa função no evento onclick da tag LABEL.

//Expandi ou recolhe os filhos do nó.
//<param name="objDiv">Div que o nó e os nós filhos estão dentro. 
</param>
//<param name="ids">Todos os identificadores dos nós filhos, 
utilizamos para expandir ou recolher eles. </param>
function nodeExpand(objDiv, ids) {
    var arrayId = ids.split(';');
    var display = '';

    var objHidden = document.getElementById(objDiv.id + 'Hidden');

    var objLabel = document.getElementById(objDiv.id + 'ClassNameHidden');

    if (objLabel.className == 'nolines_PlusTree' || 
    objLabel.className == 'nolines_MinusTree') {
        if (objLabel.className == 'nolines_PlusTree') {
            objLabel.className = 'nolines_MinusTree';
        }
        else {
            objLabel.className = 'nolines_PlusTree';
        }
    }
    else if (objLabel.className == 'plusBottomTree' || 
    objLabel.className == 'minusBottomTree') {
        if (objLabel.className == 'plusBottomTree') {
            objLabel.className = 'minusBottomTree';
        }
        else {
            objLabel.className = 'plusBottomTree';
        }
    }
    else if (objLabel.className == 'plusTree' || 
    objLabel.className == 'minusTree') {
        if (objLabel.className == 'plusTree') {
            objLabel.className = 'minusTree';
        }
        else {
            objLabel.className = 'plusTree';
        }
    }

    if (objHidden.value == '0') {
        display = 'block';
        objHidden.value = '1';
    }
    else {
        display = 'none';
        objHidden.value = '0';
    }

    for (var i = 0; i < arrayId.length - 1; i++) {
        var objNode = document.getElementById(arrayId[i]);

        objNode.style.display = display;
    }
}

Próxima função foi criada para montar o TreeView.

function loadTreeView(objContent) {
    objTreeView = new treeView();

    var objRoot = objTreeView.addNodeRoot(0, 'Node Raiz', 'Imagens/globe.gif', true);

    objRoot.addNode(1, 'Node 1', 'Imagens/page.gif', false);

    var objChild2 = objRoot.addNode(2, 'Node 2', 'Imagens/base.gif', false);
    var objChild3 = objChild2.addNode(3, 'Node 3', 'Imagens/base.gif', false, 
    'http://www.uol.com.br');
    var objChild4 = objChild3.addNode(4, 'Node 4', 'Imagens/base.gif', false);

    objChild4.addNode(5, 'Node 5', 'Imagens/page.gif', false);

    objChild2.addNode(6, 'Node 6', 'Imagens/page.gif', false);

    var objChil4 = objRoot.addNode(7, 'Node 7', 'Imagens/base.gif', false);
    objChil4.addNode(8, 'Node 8', 'Imagens/page.gif', false);

    objRoot.addNode(9, 'Node 9', 'Imagens/page.gif', false);

    objContent.innerHTML = objTreeView.contentHtml();            
}

Abaixo a visualização do TreeView no browser.

img