Creación de Estructuras de Árbol Jerárquico con Componentes Vue a partir de Datos de Objetos de Array

Este artículo detalla cómo generar una representación visual de datos jerárquicos, estructurados como un array de objetos, utilizando componentes de Vue.js. El objetivo es presentar estos datos en un formato de árbol expanidble/colapsable, con niveles de anidamiento visualmente indicados por sangrías. Se aplicará un estilo de fondo distintivo a los elementos en el quinto nivel de profundidad y se colorearán ciertas métricas clave para resaltar su significado.

Componente Reutilizable para la Estructura de Árbol

Se define un componente Vue llamado TreeNode que se encarga de renderizar cada nodo del árbol. Este componente recibe datos de un nodo como una propiedad y utiliza recursión para renderizar sus hijos. La plantilla del componente maneja la visualización de los datos del nodo y la lógica para expandir o contraer subárboles.

<script type="text/x-template" id="tree-node-template">
 <div class="node-container">
   <div class="node-header" @click="toggleExpansion">
     <span class="node-level" v-if="node.id !== 'root'">{{ node.id }}</span>
     <span class="node-name">{{ node.name }}</span>
     <span class="node-metric-1">{{ node.metric1 }}</span>
     <span class="node-metric-2">{{ node.metric2 }}</span>
     <span class="node-ratio" :class="{'is-high': node.ratio > 100, 'is-low': node.ratio < 0}">
       {{ node.ratio }}%
     </span>
   </div>
   <div class="node-children" v-show="isExpanded">
     <tree-node v-for="(child, index) in node.children" :key="index" :node="child" :level="level + 1"></tree-node>
   </div>
 </div>
</script>

Implementación del Componente Principal y Datos de Ejemplo

El componente principal App o un componente raíz similar es responsable de obtener los datos jerárquicos y pasarlos al componente TreeNode inicial. La estructura de datos de ejemplo simula un escenario real con múltiples niveles de anidamiento y métricas asociadas. La directiva v-for se utiliza para iterar sobre los datos y crear instancias del componente TreeNode de forma recursiva.


/* Estructura de datos de ejemplo */
const hierarchicalData = [{
 name: "Consumo Total",
 id: "0",
 metric1: 14410,
 metric2: 1230,
 ratio: -36.8,
 children: [{
   name: "Consumo Eléctrico Inquilinos",
   id: "1",
   metric1: 14410,
   metric2: 1230,
   ratio: -36.8,
   children: []
 }, {
   name: "Consumo Eléctrico Común",
   id: "2",
   metric1: 14410,
   metric2: 1230,
   ratio: -36.8,
   children: [{
     name: "Climatización (HVAC)",
     id: "2.1",
     metric1: 14410,
     metric2: 1230,
     ratio: -36.8,
     children: [{
       name: "Estación Frigorífica",
       id: "2.1.1",
       metric1: 14410,
       metric2: 1230,
       ratio: -36.8,
       children: [{
         name: "Unidades Enfriadoras",
         id: "2.1.1.1",
         metric1: 14410,
         metric2: 1230,
         ratio: -36.8,
         children: []
       }]
     }, {
       name: "Estación Térmica",
       id: "2.1.2",
       metric1: 14410,
       metric2: 1230,
       ratio: -36.8,
       children: []
     }]
   }]
 }]
}];

/* Registro del componente TreeNode */
Vue.component('tree-node', {
 template: '#tree-node-template',
 props: {
   node: {
     type: Object,
     required: true
   },
   level: {
     type: Number,
     default: 0
   }
 },
 data() {
   return {
     isExpanded: true // Inicialmente expandido
   };
 },
 methods: {
   toggleExpansion(event) {
     event.stopPropagation(); // Evita la propagación del evento
     this.isExpanded = !this.isExpanded;
   }
 },
 computed: {
   // Estilos para aplicar sangría basada en el nivel
   indentStyle() {
     return {
       'padding-left': `${this.level * 30}px`
     };
   }
 }
});

/* Creación de la instancia de Vue */
new Vue({
 el: '#app',
 data: {
   rootData: hierarchicalData
 }
});

Estilos CSS para la Representación Visual

Los estilos CSS son cruciales para lograr la apariencia deseada. Se definen reglas para controlar la disposición de los elementos, la sangría para indicar la jerarquía, y la aplicación de clases condicionales (is-high, is-low) para colorear las métricas según sus valores. Se aplica un color de fondo específico a los nodos que alcanzan el quinto nivel de profundidad, utilizando la anidación de selectores CSS para lograr este efecto.


.node-container {
 margin-bottom: 5px;
}

.node-header {
 display: flex;
 align-items: center;
 height: 35px;
 border-bottom: 1px solid #eee;
 padding: 0 10px;
 cursor: pointer;
 box-sizing: border-box;
 background-color: #fff;
}

.node-header .node-level {
 min-width: 40px;
 text-align: center;
 margin-right: 10px;
 color: #888;
}

.node-header .node-name {
 flex-grow: 1;
 text-align: left;
 white-space: nowrap;
 overflow: hidden;
 text-overflow: ellipsis;
 margin-right: 10px;
}

.node-header span {
 display: inline-block;
 min-width: 80px; /* Ancho fijo para métricas */
 text-align: center;
 box-sizing: border-box;
 border-right: 1px solid #eee;
 padding-right: 5px; /* Espacio para el borde */
}

.node-header span:last-child {
 border-right: none;
 padding-right: 0;
}

.node-header .node-ratio {
 min-width: 70px; /* Ancho para porcentaje */
}

.node-children {
 overflow: hidden;
 background-color: #f9f9f9;
}

/* Estilos para la sangría recursiva */
.node-container .node-children .node-header {
 padding-left: 40px; /* Sangría base para hijos */
}
.node-container .node-children .node-children .node-header {
 padding-left: 70px;
}
.node-container .node-children .node-children .node-children .node-header {
 padding-left: 100px;
}
.node-container .node-children .node-children .node-children .node-children .node-header {
 padding-left: 130px;
}
.node-container .node-children .node-children .node-children .node-children .node-children .node-header {
 padding-left: 160px;
 background-color: #f0f0f0; /* Color de fondo para el 5to nivel */
}

.is-high {
 color: red;
}

.is-low {
 color: green;
}

Etiquetas: vue.js componentes Estructura de Datos recursion Jerarquía

Publicado el 6-26 22:32