En Vue cada instancia de un componente tiene su ámbito (scope) aislado del resto. Esto quiere decir que una instancia no debe referenciar directamente los datos de otra instancia, lo que refuerza que el estado de la aplicación no pueda ser mutado descontroladamente. Para pasar datos desde un componente a sus hijos se utilizan propiedades, y desde los hijos a su padres se usan eventos. ¿Pero, y a la instancia principal, que no tiene padres, como le hacemos llegar datos para inicializarla?
Como es habitual para mostrar como podemos realizar el paso de parámetros vamos a desarrollar un programa de ejemplo. Empezaremos con el esqueleto generado por la linea de comandos de vue,vue-cli
.Si no sabes como hacerlo puedes revisar la primera parte del articulo anterior donde puedes ver los pasos detallados.
Una vez creada la estructura, podemos ver el html básico de nuestra aplicacion en index.html:
<body> <div id="app"></div> <script src="/dist/build.js"></script> </body>
La aplicación Vue se renderizará sustituyendo al elemento con id=»app» de acuerdo a la definición por del componente principal que podemos ver en src\main.js
import Vue from 'vue' import App from './App.vue' new Vue({ el: '#app', render: h => h(App) })
Nuestro objetivo es poder pasarle al componente principal un parámetro que definiremos en el html:
<div id="app" parametro="valor"> </div>
En Vue 1.0 esto podía lograrse de manera sencilla utilizando el mismo método que se utiliza para pasar parametros a una instancia hija:
new Vue( { el: '#app', props :["parametro"], .....
Sin embargo, esto no funciona en la versión 2 de Vue, y no hay descrita en la documentación oficial ninguna manera de hacerlo.
Utilizando el evento beforeMount
Si echamos un vistazo al diagrama del ciclo de vida de una instancia Vue podemos ver que, justo antes de que el elemento html que se va a sustituir sea eliminado del DOM en favor de la propia instancia se lanza el evento beforeMount. Lo que vamos a hacer es aprovechar este punto para leer los atributos del elemento y guardarlos en propiedades que pasaremos a nuestra instancia. Modificamos por tanto main.js para poner un hook en el evento beforeMount de la siguiente manera:
import App from './App.vue' new Vue({ el: '#app', data: {parametro:null}, render: h => h(App) beforeMount: function () { this.parametro= this.$el.attributes['parametro'].value; } })
Hemos creado una variable con el nombre parámetro y la inicializamos con el valor del atributo parámetro del elemento html a sustituir, que durante el evento podemos referenciar como this.$el . La creación de la variable parámetro en la sección data no es realmente necesaria, ya que al establecer this.parametro en beforeMount ya estamos creando una variable en el objeto javascript que representa la instancia, pero la creamos por claridad.
Ya tenemos el valor del atributo recogido en una variable, pero nos falta hacérselo llegar a nuestro componente. vue-cli
crea el componente raíz por defecto mediante la función render del objeto Vue. Si bien podríamos pasar el valor leído en esta función, vamos a optar por una forma de hacerlo que resulte más clara y homogénea con el funcionamiento de Vue mediante el uso de un template y haciendo un binding de variable:
new Vue({ el: '#app', components: {App}, template: '<App :parametro="parametro" />', data: { parametro: null }, beforeMount: function () { this.parametro = this.$el.attributes['parametro'].value; } });
Por último, ya solo nos falta recoger esta propiedad en el componente src/App.vue declarándola en el array props:
<template> <div id="app"> <img src="./assets/logo.png"> <h1>Parametro raíz: {{ parametro }}</h1> </div> </template> <script> export default { name: "app", props: ["parametro"] }; </script>