English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
En Vue.js, un componente recursivo llama a sí mismo, como:
Vue.component('recursive-component', { template: `<!--Invocándome a mí mismo!--> <recursive-component></recursive-component>` });
Los componentes recursivos se utilizan comúnmente para mostrar comentarios en blogs, menús anidados o básicamente tipos de padre e hijo iguales, aunque el contenido sea diferente. Por ejemplo:
Ahora le mostraré cómo usar efectivamente el componente recursivo, creando un componente expandible/Procederemos paso a paso con un menú de árbol colapsado.
Estructura de datos
Un componente de UI en forma de árbol es una expresión visual de estructuras de datos recursivas. En este tutorial, utilizaremos estructuras de árbol donde cada nodo es un objeto:
Una propiedad de label.
Si tiene nodos secundarios, una propiedad de nodes, es un array de uno o más nodos.
Como cualquier estructura de árbol, debe tener un nodo raíz, pero puede ser infinitamente profundo.
let tree = { label: 'root', nodes: [ { label: 'item'1', nodes: [ { label: 'item'1.1' }, { label: 'item'1.2', nodes: [ { label: 'item'1.2.1' } ] } ] }, { label: 'item'2' } ] }
Componente recursivo
Hagamos un componente recursivo para mostrar nuestra estructura de datos llamada TreeMenu. Solo muestra la etiqueta del nodo actual y llama a sí mismo para mostrar cualquier nodo secundario. El nombre del archivo es TreeMenu.vue, y el contenido es el siguiente:
<template> <div class="tree-menu> <div>{{ label }}</div> <tree-menu v-for="node in nodes" :nodes="node.nodes" :label="node.label" > </tree-menu> </div> </template> <script> export default { props: [ 'label', 'nodes' ], name: 'tree-menu' } </script>
Si usas un componente recursivo, debes hacer una definición global de Vue.component primero, o, dale un atributo de nombre. De lo contrario, cualquier componente secundario no podrá llamarlo, y obtendrás un mensaje de error de "undefined component" incierto.
Evento básico
Como cualquier función recursiva, necesitas un evento básico para terminar la recursión, de lo contrario, el renderizado continuará indefinidamente y finalmente causará un desbordamiento de pila.
En el menú de árbol, cuando alcanzamos un nodo sin nodos hijos, queremos detener la recursión. ¿Puedes hacerlo a través de v-if puede lograr esta función, pero elegimos usar v-for implícitamente lo implementará por nosotros; si el array de nodes no tiene una definición adicional tree-El componente de menú será llamado. El archivo template.vue es el siguiente:
<template> <div class="tree-menu> ... <!--Si `nodes` no está definido, esto no se renderizará--> <tree-menu v-for="node in nodes"></tree-menu> </template>
Uso
¿Cómo usamos este componente? Primero, declaramos una instancia Vue, que tiene una estructura de datos que incluye la propiedad data y el componente definido treemenu. El archivo app.js es el siguiente:
import TreeMenu from '.'/TreeMenu.vue' let tree = { ... } new Vue({ el: '#app', data: { tree }, components: { TreeMenu } )
Recuerda, nuestra estructura de datos tiene un nodo raíz. En el plantilla principal, llamamos recursivamente al componente TreeMenu, utilizando la propiedad nodes raíz para props:
<div id="app"> <tree-menu :label="tree.label" :nodes="tree.nodes"></tree-menu> </div>
Aquí está su aspecto actual:
Postura correcta
Es bueno identificar visualmente la "profundidad" del componente subyacente, de modo que el usuario pueda obtener una sensación de la estructura de datos desde la UI. Vamos a sangrar cada nivel de nodos hijos para lograr este objetivo.
Esto se logra aumentando un prop depth definido, que se realiza a través de TreeMenu. Usaremos este valor para vincular estilos dinámicamente: usaremos la regla CSS transform: translate para cada etiqueta del nodo, creando así sangría. La modificación del archivo template.vue es la siguiente**:}}**
<template> <div class="tree-menu> <div :style="indent">{{ label }}</div> <tree-menu v-for="node in nodes" :nodes="node.nodes" :label="node.label" :depth="depth + 1" > </tree-menu> </div> </template> <script> export default { props: [ 'label', 'nodes', 'depth' ], name: 'tree-menu', computed: { indent() { return { transform: `translate(${this.depth * 50}px)` } } } } </script>
La propiedad depth comienza en cero en el plantilla principal. En el componente de plantilla superior, puedes ver que este valor aumenta cada vez que se pasa a cualquier nodo hijo.
<div id="app"> <tree-menu :label="tree.label" :nodes="tree.nodes" :depth="0" ></tree-menu> </div>
Nota: recuerda v-bindeo el valor depth para asegurarme de que sea un tipo de número JavaScript en lugar de una cadena.
Expandir/Colapsar
Dado que las estructuras de datos recursivas pueden ser muy grandes, una buena técnica UI para mostrarlas es ocultar todos los nodos excepto el nodo raíz, para que el usuario pueda expandir o colapsar los nodos según sea necesario.
Por lo tanto, agregaremos una propiedad local showChildren. Si su valor es False, los nodos hijos no se renderizarán. Este valor debe cambiarse mediante un evento de clic para cambiar de nodo, por lo que necesitamos usar un método de escucha de eventos de clic toggleChildren para gestionarlo. La modificación del archivo template.vue es la siguiente**:}}**
<template> <div class="tree-menu> <div :style="indent" @click="toggleChildren">{{ label }}</div> <tree-menu v-if="showChildren" v-for="node in nodes" :nodes="node.nodes" :label="node.label" :depth="depth + 1" > </tree-menu> </div> </template> <script> export default { props: [ 'label', 'nodes', 'depth' ], data() { return { showChildren: false } }, name: 'tree-menu', computed: { indent() { return { transform: `translate(${this.depth * 50}px)` } } }, methods: { toggleChildren() { this.showChildren = !this.showChildren; } } } </script>
Resumen
De esta manera, tenemos un menú de árbol operativo. Un método para completar la pintura es agregar un icono de más./Icono de guión, lo que hace que la visualización de la UI sea más clara. También agregué muy buenas fuentes y rendimiento de cálculo en la base de showChildren.
Ir a CodePen ( https://codepen.io/anthonygore/pen/PJKNqaPuedes ver cómo lo hice.