Creación de instancias de componentes Vue.js mediante programación | Programar Plus

Este artículo asume una comprensión básica del marco Vue.js y cómo crear componentes en él. Si es nuevo en Vue, entonces esta serie de Programar Pluses un buen lugar para comenzar.

Estuve en un proyecto de Vue.js que requería la capacidad de crear componentes mediante programación. Por programación, quiero decir que crea e inserta los componentes completamente desde JavaScript, sin escribir nada en la plantilla. Este artículo tiene como objetivo ilustrar cómo los diferentes aspectos del uso de componentes en una plantilla, como la creación de instancias, el paso de accesorios, las ranuras, el montaje, se traducen en código JavaScript.

Normalmente, si está trabajando con el recomendado Componente de archivo único estilo, tendrías un Button componente así:

<template>
 <button :class="type"><slot /></button>
</template>
<script>
 export default {
   name: 'Button',
   props: [ 'type' ],
 }
</script>

Para usarlo en otro componente, todo lo que tiene que hacer es importar el Button componente e inserte su etiqueta en la plantilla:

<template>
 <Button type="primary">Click me!</Button>
</template>
<script>
 import Button from 'Button.vue'
 export default {
   name: 'App',
   components: { Button }
 }
</script>

En mi caso, no sé qué componente insertar en la plantilla y tampoco dónde insertarlo. Esta información solo está disponible en tiempo de ejecución. Así que necesitaba una forma de crear dinámicamente una instancia de componente para cualquier componente pasado e insertarlo en el DOM, durante el tiempo de ejecución.

Crear la instancia

La primera idea que tuve para crear una instancia dinámica de un componente dado fue pasarlo a new y me daría la instancia real. Pero si te fijas bien en la script bloque en cualquiera de los códigos de componentes anteriores, todos están exportando un objeto simple, y no una clase (función de constructor). Si hago esto:

import Button from 'Button.vue'
var instance = new Button()

…fracasa. Necesitamos una clase. O, en términos simples, una función constructora. La forma de hacerlo es pasar el objeto componente a Vue.extend para crear una subclase de la Vue constructor. Ahora podemos crear una instancia a partir de él con el new palabra clave:

import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass()

¡Hurra! ¡Paso 1 superado! Ahora necesitamos insertarlo en el DOM.

Insertar en DOM

Cada instancia de Vue tiene un método llamado $mount en él, que monta la instancia del componente en el elemento que le pasa (es decir, reemplaza el elemento pasado con la instancia del componente). Este no es un comportamiento que yo quería. Quería insertar mis instancias de componentes dentro de algún elemento DOM. Hay una manera de hacer eso también. De los documentos oficiales:

Si no se proporciona el argumento elementOrSelector, la plantilla se representará como un elemento fuera del documento y tendrá que usar la API DOM nativa para insertarla en el documento usted mismo.

Eso fue lo que hice:

import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass()
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)

Hay un par de cosas a tener en cuenta en el código anterior.

Primero, $refs es la forma recomendada de obtener una referencia a un elemento DOM en Vue.js. Usted especifica un atributo en el elemento DOM al que desea hacer referencia (<div ref="container"></div> en este caso) y luego ese elemento está disponible en la tecla set en el componente $refs propiedad.

En segundo lugar, para obtener la referencia del elemento DOM nativo de una instancia de componente Vue, puede usar el $el propiedad.

Pasar accesorios a la instancia

A continuación, tuve que pasar algunos accesorios a mi Button ejemplo. Específicamente, el type apuntalar. El Vue La función constructora acepta un objeto de opciones que podemos usar para pasar e inicializar cosas relacionadas. Para pasar props, hay una clave llamada propsData que podemos usar, así:

import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass({
    propsData: { type: 'primary' }
})
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)

Casi hemos terminado, con un bit final restante. Con el método de plantilla normal, usamos botones como: <Button>Click me!</Button>;. Simplemente escribimos el texto interno entre las etiquetas y lo representamos dentro de la etiqueta del botón final con la ayuda de slot. Pero ahora, ¿cómo lo pasamos?

Configuración de la ranura

Si ha utilizado ranuras en Vue.js, es posible que sepa que se puede acceder a las ranuras en cualquier instancia en el $slots propiedad. Y si no se utilizan ranuras con nombre, las ranuras están disponibles en $slots.default como una matriz. Esa es la clave exacta que modificaremos en la instancia para configurar el texto interno de nuestro botón. Recuerde, esto debe hacerse antes de montar la instancia. Tenga en cuenta que, en nuestro caso, simplemente colocamos una cadena simple en la ranura porque eso es todo lo que necesitamos. Pero puede pasarle DOM más complejo en forma de nodos virtuales o VNode usando el createElement función. Puede leer sobre la creación de nodos virtuales en la documentación de Vue.js. Gracias a un miembro del equipo central de Vue, Raúl, por sugerir esta técnica.

import Button from 'Button.vue'
import Vue from 'vue'
var ComponentClass = Vue.extend(Button)
var instance = new ComponentClass({
    propsData: { type: 'primary' }
})
instance.$slots.default = [ 'Click me!' ]
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)

demostración final

Ver demostración

Espero que te haya gustado este artículo. Sigueme en Twitter donde comparto más artículos y proyectos paralelos míos.

(Visited 2 times, 1 visits today)