Vue2 Handbook
Vue2 Handbook
js
Handbook
Cesar Meloni
Bajo el capó, Vue compila las templates en funciones de renderizado del DOM virtual. Combinado con el sistema
de reactividad, Vue puede averiguar de manera inteligente el número mínimo de componentes para volver a
renderizar y aplicar la cantidad mínima de manipulacion del DOM cuando el estado de la aplicacion cambia.
Si está familiarizado con los conceptos de DOM virtual y prefiere la potencia bruta de JavaScript, también
puede escribir directamente funciones de procesamiento en lugar de plantillas, con soporte opcional de JSX.
Interpolaciones
Texto
La forma más básica de enlace de datos es la interpolación de texto usando la sintaxis de mustaches (llaves
doble):
También puede realizar interpolaciones únicas que no se actualizan en el cambio de datos usando la directiva v-
once, pero tenga en cuenta que esto también afectará a cualquier otro enlace en el mismo nodo:
HTML Puro
Los mustaches (llaves doble) interpretan los datos como texto plano, no HTML. Para generar HTML real, deberá
utilizar la directiva v-html:
El contenido del span se reemplazará con el valor de la propiedad rawHtml, interpretado como HTML simple: se
ignoran los enlaces de datos. Tenga en cuenta que no puede utilizar v-html para componer plantillas parciales,
porque Vue no es un motor de plantillas basado en cadenas. En cambio, se prefieren los componentes como la
unidad fundamental para la reutilización y la composición de la interfaz de usuario.
La ejecución dinámica de HTML arbitrario en su sitio web puede ser muy peligrosa porque puede conducir
fácilmente a vulnerabilidades de XSS. Utilice solo la interpolación HTML en contenido de confianza
y nunca en contenido proporcionado por usuario.
Atributos
Los mustaches (llaves doble) no se pueden utilizar dentro de los atributos HTML. En su lugar, use una directiva v-
bind:
<div v-bind:id="dynamicId"></div>
<button v-bind:disabled="isButtonDisabled">Button</button>
Hasta ahora solo hemos estado vinculando a simples claves de propiedad en nuestras template. Pero Vue.js
realmente admite el poder completo de las expresiones de JavaScript dentro de todos los enlaces de datos:
Estas expresiones se evaluarán como JavaScript en el ámbito de datos de la instancia de Vue del propietario. Una
restricción es que cada enlace solo puede contener una expresión, por lo que lo siguiente NO funcionará:
Las expresiones de template están en un espacio aislado y solo tienen acceso a una lista blanca de
elementos globales como Matemáticas y Fecha. No debe intentar acceder a globales definidos por el
usuario en expresiones de template.
Directivas
Las directivas son atributos especiales con el prefijo v-. Se espera que los valores de atributo de la directiva
sean una única expresión de JavaScript (con la excepción de v-for, que se tratará más adelante). El trabajo de
una directiva es aplicar reactivamente efectos secundarios al DOM cuando cambia el valor de su expresión.
Repasemos el ejemplo que vimos en la introducción:
Argumentos
Algunas directivas pueden tomar un “argumento”, denotado por dos puntos después del nombre de la directiva.
Por ejemplo, la directiva v-bind se usa para actualizar de forma reactiva un atributo HTML:
Aquí el argumento es el nombre del evento a escuchar. Hablaremos sobre el manejo de eventos con más detalle
también.
Modificadores
Los modificadores son sufijos especiales indicados por un punto, que indican que una directiva debe estar
vinculada de alguna manera especial. Por ejemplo, el modificador .prevent le dice a la directiva v-on que
llame a event.preventDefault() en el evento activado:
Modo abreviado
El prefijo v- sirve como una señal visual para identificar atributos específicos de Vue en sus templates. Esto es útil
cuando está utilizando Vue.js para aplicar un comportamiento dinámico a algún marcado existente, pero puede
sentirse detallado para algunas directivas de uso frecuente. Al mismo tiempo, la necesidad del prefijo v- es
menos importante cuando se está construyendo un SPA donde Vue.js administra cada template. Por lo tanto,
Vue.js proporciona abreviaturas especiales para dos de las directivas más utilizadas, v-bind y v-on:
v-bind Abreviado
v-on Abreviado
Pueden parecer un poco diferentes del HTML normal, pero : y @ son caracteres válidos para los nombres de
atributos y todos los navegadores compatibles con Vue.js pueden analizarlo correctamente. Además, no aparecen
en el marcado final renderizado. La sintaxis abreviada es totalmente opcional, pero es probable que la aprecie
cuando sepa más sobre su uso más adelante.
Propiedades Computadas
Las expresiones en el template son muy convenientes, pero están diseñadas para operaciones simples. Poner
demasiada lógica en sus templates puede hacerlos grandes, complejos y difíciles de mantener. Por ejemplo:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
En este punto, el template ya no es simple y declarativo. Debe mirarlo por un segundo antes de darse cuenta de
que muestra message al revés. El problema se agrava cuando desea incluir el mensaje invertido en
su template más de una vez.
Es por eso que para cualquier lógica compleja, deberia usar una propiedad computada.
Ejemplo Básico
<div id="example">
<p>Mensaje original: "{{ message }}"</p>
Puede abrir la consola y jugar con el ejemplo vm usted mismo. El valor de vm.reversedMessage siempre
depende del valor de vm.message.
Puede enlazar datos a propiedades computadas en el template al igual que una propiedad normal. Vue es
consciente de que vm.reversedMessage depende de vm.message, por lo cual actualizará todos los enlaces
que dependan de vm.reversedMessage cuando vm.message cambie. Y lo mejor de todo es que hemos
creado esta relación de dependencia de manera declarativa: la función computada getter no tiene efectos
secundarios, lo que facilita la prueba y la comprensión.
Es posible que haya notado que podemos lograr el mismo resultado al invocar un método en la expresión:
En lugar de una propiedad computada, podemos definir la misma función como un método en su lugar. Para el
resultado final, los dos enfoques son exactamente los mismos. Sin embargo, la diferencia es que las propiedades
computadas se almacenan en caché según sus dependencias. Una propiedad computada solo se volverá a
evaluar cuando alguna de sus dependencias haya cambiado. Esto significa que mientras message no haya
cambiado, el acceso múltiple a la propiedad computada de reverseMessage regresará inmediatamente el
resultado previamente calculado sin tener que ejecutar la función de nuevo.
Esto también significa que la siguiente propiedad computada nunca se actualizará, porque Date.now() no es
una dependencia reactiva:
computed: {
now: function () {
return Date.now()
}
}
En comparación, una invocación de método siempre ejecutará la función cada vez que ocurre una re-
renderizacion.
¿Por qué necesitamos caché? Imagina que tenemos una costosa propiedad computada A, que requiere hacer un
bucle a través de una gran matriz y hace muchos cálculos. Entonces podemos tener otras propiedades
computadas que a su vez dependen de A. Sin caché, estaríamos ejecutando el captador de A muchas veces más
de lo necesario. En los casos en que no desee el almacenamiento en caché, utilice un método en su lugar.
Vue proporciona una forma más genérica de observar y reaccionar a los cambios de datos en una instancia de
Vue: propiedad watch. Cuando tiene algunos datos que necesitan cambiarse en función de otros datos, es
tentador utilizar watch en exceso, especialmente si proviene de tener experiencia en AngularJS. Sin embargo, a
menudo es una mejor idea usar una propiedad computada en lugar de una imperativa llamada a watch .
Considera este ejemplo:
El código anterior es imperativo y repetitivo. Compáralo con una versión de propiedad computada:
Setter Computado
Las propiedades computadas son, de forma predeterminada solo get, pero también puede proporcionar un set
cuando lo necesite:
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
Watchers
Si bien las propiedades computadas son más apropiadas en la mayoría de los casos, hay ocasiones en que es
necesario un observador personalizado. Es por eso que Vue proporciona una forma más genérica de reaccionar a
los cambios de datos a través de la opción watch. Esto es más útil cuando desea realizar operaciones asíncronas
o costosas en respuesta al cambio de datos.
por ejemplo:
<div id="watch-example">
<p>
Haz una pregunta de sí/no:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- Dado que ya existe un rico ecosistema de bibliotecas ajax -->
<!-- y colecciones de métodos de utilidad de uso general, Vue core -->
<!-- es capaz de permanecer pequeño al no reinventarlos. Esto también -->
<!-- te da la libertad de usar aquello con lo que estás familiarizado. -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'No puedo darte una respuesta hasta que hagas una pregunta!'
},
watch: {
// cada vez que la pregunta cambie, esta función será ejecutada
question: function (newQuestion, oldQuestion) {
this.answer = 'Esperando que deje de escribir...'
this.debouncedGetAnswer()
}
},
created: function () {
// _.debounce es una función proporcionada por lodash para limitar cuan
Result:
En este caso, el uso de la opción watch nos permite realizar una operación asíncrona (acceder a una API), limita
la frecuencia con la que realizamos esa operación y establece estados intermedios hasta que obtengamos una
respuesta final. Nada de eso sería posible con una propiedad computada.
Sintaxis de Objeto
Puede hacer multiple asignación de clases al tener más campos en el objeto. Además, la directiva v-
bind:class también puede ser utilizada con el atributo class. De modo que con la siguiente plantilla:
<div class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
Y el siguiente objeto data:
data: {
isActive: true,
hasError: false
}
Se renderizará:
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
Esto renderizará el mismo resultado. También podemos enlazar una propiedad computada que retorna un
objeto. Esto es un patrón común y poderoso:
<div v-bind:class="classObject"></div>
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
Sintaxis de Array
Que renderizará:
Sin embargo, esto puede ser un poco verborrágico si usted tiene multiple clases condicionales. Por eso también
es posible utilizar la sintaxis de objeto dentro de la sintaxis de colección:
Con Componentes
Esta sección asume que usted tiene conocimientos sobre Componentes de Vue. Siéntase libre
de saltársela y volver más tarde.
Cuando usa el atributo class en un componente personalizado, estas clases se agregarán al elemento raíz del
componente. Las clases existentes en este elemento no serán sobreescritas.
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})
Sintaxis de Objeto
La sintaxis de objeto para v-bind:style es muy sencilla - es similar a CSS, excepto que es un objeto
JavaScript. Puede usar tanto camelCase como kebab-case (use comillas con kebab-case) para los nombres de
propiedades CSS:
A menudo es una buena idea enlazar directamente un objeto de estilo para que la plantilla sea más limpia:
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
Nuevamente, la sintaxis de objeto es a menudo usada en conjunción con propiedades computadas que retornan
objetos.
Sintaxis de Array
Cuando utilice una propiedad CSS que requiera prefijos de proveedores en v-bind:style, como por
ejemplo transform, Vue detectará automaticamente y agregará los prefijos correspondientes a los estilos
aplicados.
Valores múltiples
2.3.0+
Desde la versión 2.3.0+ usted puede proveer un array de valores múltiples (de prefijos) a una propiedad de estilo,
por ejemplo:
Esto solo renderizará el ultimo valor en el array que el navegador soporte. En este ejemplo, se
renderizará display: flex para los navegadores que soportan la versión sin prefijo de flexbox.
v-if
En los string templates, como por ejemplo, Handlebars, escribiríamos un bloque condicional como este:
<h1 v-if="ok">Sí</h1>
<h1 v-if="ok">Sí</h1>
<h1 v-else>No</h1>
Debido a que v-if es una directiva, debe adjuntarse a un solo elemento. Pero, ¿y si queremos cambiar más de
un elemento? En este caso, podemos usar v-if en un elemento<template>, que sirve como un envoltorio
invisible. El resultado final procesado no incluirá el elemento <template>.
<template v-if="ok">
<h1>Título</h1>
<p>Párrafo 1</p>
<p>Párrafo 2</p>
</template>
v-else-if
Nuevo en 2.1.0+
El v-else-if, como su nombre lo indica, sirve como “bloque else if“ para v-if. También puede ser
encadenado varias veces:
Vue intenta representar los elementos de la manera más eficiente posible, a menudo reutilizándolos en lugar de
renderizarlos desde cero. Más allá de ayudar a hacer Vue muy rápido, esto puede tener algunas ventajas útiles.
Por ejemplo, si permite a los usuarios alternar entre varios tipos de inicio de sesión:
Luego, cambiando el loginType en el código anterior no borrará lo que el usuario ya ha ingresado. Dado que
ambos templates utilizan los mismos elementos, el <input> no se reemplaza, solo su placeholder.
Sin embargo, esto no siempre es deseable, por lo que Vue le ofrece una manera de decir: “Estos dos elementos
están completamente separados, no los reutilice”. Agregue un atributo key con valores únicos:
v-show
<h1 v-show="ok">Hola!</h1>
Observe que el uso de v-show no es compatible con elementos <template>, ni tampoco funciona con v-
else.
v-if vs v-show
v-if es una renderización condicional “real” ya que garantiza que los eventos y componentes secundarios
dentro del bloque condicional sean debidamente destruidos y recreados durante la alternancia.
v-if también es lazy: si la condición es falsa en la representación inicial, no se hará nada. El bloque condicional
no se procesará hasta que la condición se convierta en true por primera vez.
v-if con v-for
Cuando es utilizado junto con v-for, este tiene una prioridad más alta que v-if. Consulte la guía de
renderización de listas para obtener más información.
Podemos usar la directiva v-for para representar una lista de elementos basada en una matriz. La directiva v-
for requiere una sintaxis especial en forma de item in items, donde los items son la matriz de datos de
origen y el item es un alias para el elemento de matriz que se está iterando:
<ul id="example-1">
<li v-for="item in items">
{{ item.mensaje }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ mensaje: 'Foo' },
{ mensaje: 'Bar' }
]
}
})
Resultado:
•Foo
•Bar
Dentro de los bloques v-for tenemos acceso completo a las propiedades del ámbito principal. v-for también
admite un segundo argumento opcional para el índice del elemento actual.
<ul id="example-2">
<li v-for="(item, index) in items">
{{ MensajePadre }} - {{ index }} - {{ item.mensaje }}
</li>
</ul>
var example2 = new Vue({
el: '#example-2',
data: {
Resultado:
•Padre - 0 - Foo
•Padre - 1 - Bar
También puede usar of como delimitador en lugar de in, de modo que esté más cerca de la sintaxis de
JavaScript para los iteradores:
v-for con un Objeto
Resultado:
•Doe
•30
primerNombre: John
apellido: Doe
edad: 30
0. primerNombre: John
1. apellido: Doe
Al iterar sobre un objeto, el orden se basa en el orden de enumeración de claves de Object.keys(), que
no se garantiza que sea consistente en todas las implementaciones del motor de JavaScript.
key
Cuando Vue está actualizando una lista de elementos representados con v-for, por defecto utiliza una
estrategia de “parche in situ”. Si el orden de los elementos de datos ha cambiado, en lugar de mover los
elementos DOM para que coincidan con el orden de los elementos, Vue aplicará parches a cada elemento en el
lugar y se asegurará de que refleje lo que se debe representar en ese índice en particular. Esto es similar al
comportamiento de track-by="$index" en Vue 1.x.
Este modo predeterminado es eficiente, pero solo es adecuado cuando la salida de renderizado de su lista no
se basa en el estado del componente secundario o el estado temporal de DOM (por ejemplo, valores de
entrada de formulario).
Para proporcionar a Vue una sugerencia para que pueda rastrear la identidad de cada nodo y, por lo tanto,
reutilizar y reordenar los elementos existentes, debe proporcionar un atributo key único para cada elemento. Un
valor ideal para key sería el ID único de cada elemento. Este atributo especial es un equivalente aproximado
a track-by en 1.x, pero funciona como un atributo, por lo que necesita usar v-bind para enlazarlo con valores
dinámicos (usando el modo abreviado aquí):
Se recomienda proporcionar una key con v-for siempre que sea posible, a menos que el contenido DOM
iterado sea simple, o esté confiando intencionalmente en el comportamiento predeterminado para obtener
ganancias en el rendimiento.
Como Vue es un mecanismo genérico para identificar nodos, la key también tiene otros usos que no están
específicamente vinculados a v-for, como veremos más adelante en la guía.
Metodos de Mutacion
Vue envuelve los métodos de mutación de una matriz observada para que también activen las actualizaciones de
vista. Los métodos envueltos son:
•push()
•pop()
•shift()
•unshift()
•splice()
•sort()
•reverse()
Puede abrir la consola y probar con la matriz de items de los ejemplos anteriores llamando a sus métodos de
mutación. Por ejemplo: example1.items.push ({mensaje: 'Baz'}).
Mutando un Array
Los métodos de mutación, como sugiere su nombre, mutan la matriz original a la que se llama. En comparación,
también hay métodos no mutantes, p. Ej. filter(), concat() y slice(), que no mutan la matriz original
pero siempre devuelven una nueva matriz. Cuando trabaje con métodos no mutantes, puede reemplazar la
matriz anterior por la nueva:
Podría pensar que esto hará que Vue elimine el DOM existente y vuelva a renderizar la lista completa;
afortunadamente, ese no es el caso. Vue implementa algunas heurísticas inteligentes para maximizar la
reutilización de elementos DOM, por lo tanto, reemplazar una matriz con otra matriz que contenga objetos
superpuestos es una operación muy eficiente.
Debido a las limitaciones en JavaScript, Vue no puede detectar los siguientes cambios en una matriz:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
vm.items.splice(newLength)
Una vez más, debido a las limitaciones del JavaScript moderno, Vue no puede detectar la adición o eliminación
de propiedades. Por ejemplo:
Vue no permite agregar dinámicamente nuevas propiedades reactivas a nivel de raíz a una instancia ya creada.
Sin embargo, es posible agregar propiedades reactivas a un objeto anidado usando el método Vue.set
(objeto, clave, valor). Por ejemplo, dado:
También puede usar el método de instancia vm. $Set, que es un alias para el Vue.set global:
En ocasiones, es posible que desee asignar varias propiedades nuevas a un objeto existente, por ejemplo,
utilizando Object.assign() o _.extend(). En tales casos, debe crear un objeto nuevo con propiedades de
ambos objetos. Así que en lugar de:
Object.assign(vm.userProfile, {
edad: 27,
favoriteColor: 'Vue Green'
})
A veces, queremos mostrar una versión filtrada u ordenada de una matriz sin mutar o restablecer los datos
originales. En este caso, puede crear una propiedad computada que devuelva la matriz filtrada o ordenada.
Por ejemplo:
En situaciones donde las propiedades computadas no son factibles (por ejemplo, dentro de los bucles v-
for anidados), puede usar un método:
v-for con un Rango
v-for también puede tomar un entero. En este caso repetirá la plantilla muchas veces.
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
Resultado:
1 2 3 4 5 6 7 8 9 10
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-for con v-if
Cuando existen en el mismo nodo, v-for tiene una prioridad más alta que v-if. Eso significa que el v-if se
ejecutará en cada iteración del bucle por separado. Esto puede ser útil cuando desea representar nodos solo
para algunos elementos, como a continuación:
Si, por el contrario, su intención es omitir condicionalmente la ejecución del bucle, puede colocar el v-if en un
elemento de envoltura (o <template>). Por ejemplo:
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No quedan todos !</p>
v-for con un Componente
Esta sección asume el conocimiento de Componentes. Siéntase libre de saltearlo y volver más
tarde.
Sin embargo, esto no pasará automáticamente ningún dato al componente, porque los componentes tienen sus
propios ámbitos aislados. Para pasar los datos iterados al componente, también debemos usar props:
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
La razón para no inyectar automáticamente el item en el componente es porque hace que el componente esté
estrechamente acoplado a cómo funciona v-for. Ser explícito acerca de dónde provienen sus datos hace que el
componente sea reutilizable en otras situaciones.
<div id="todo-list-example">
<form -on:submit.prevent="addNewTodo">
<label for="new-todo">Agregar tarea</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder=E.g. Feed the cat"
>
<button>Agregar</button>
</form>
<ul>
<li
is="todo-item"
v-for="(todo, index) in todos"
v-bind:key="todo.id"
v-bind:title="todo.title"
v-on:remove="todos.splice(index, 1)"
></li>
</ul></div>
Note el atributo is = "todo-item". Esto es necesario en las plantillas DOM, porque solo un
elemento <li> es válido dentro de un <ul>. Hace lo mismo que <todo-item>, pero funciona alrededor
de un error potencial de análisis del navegador. Ver las advertencias de análisis de plantillas
DOM aprender más.
.component('todo-item', {
template: '\
<li>\
{{ title }}\
<button -on:click="$emit(\'remove\')">Remove</button>\
</li>\
Escuchar eventos
Podemos usar la directiva v-on para escuchar eventos DOM y ejecutar algunos JavaScript cuando se activan.
Por ejemplo:
<div id="example-1">
<button v-on:click="counter += 1">Add 1</button>
<p>Se ha hecho clic en el botón de arriba {{ counter }} veces.</p>
</div>
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0
}
})
Sin embargo, la lógica para muchos controladores de eventos será más compleja, por lo que no es posible
mantener su JavaScript en el valor del atributo v-on. Es por eso que v-on también puede aceptar el nombre de
un método al que te gustaría llamar.
Por ejemplo:
<div id="example-2">
<!-- `saludar` es el nombre de un método definido a continuación -->
<button v-on:click="saludar">Saludar</button>
</div>
var example2 = new Vue({
el: '#example-2',
data: {
name: 'Vue.js'
},
// definir métodos bajo el objeto `methods`
methods: {
saludar: function (event) {
// `this` dentro de los métodos apunta a la instancia de Vue
alert('Hola ' + this.name + '!')
// `evento` es el evento DOM nativo
if (event) {
En lugar de enlazar directamente con un nombre de método, también podemos usar métodos en una declaración
de JavaScript en línea:
<div id="example-3">
<button v-on:click="di('hola')">Di hola</button>
<button v-on:click="di('que')">Di que</button>
</div>
new Vue({
el: '#example-3',
methods: {
di: function (mensaje) {
alert(mensaje)
}
}
})
A veces también necesitamos acceder al evento DOM original en un controlador de instrucciones en línea. Puedes
pasarlo a un método usando la variable especial $event:
Para solucionar este problema, Vue proporciona modificadores de eventos para v-on. Recuerde que los
modificadores son directivas postfijos marcados por un punto.
•.stop
•.prevent
•.capture
•.self
•.once
•.passive
<!-- Se detendrá la propagación del evento click. -->
<a v-on:click.stop="hasEsto"></a>
<!-- El evento de enviar ya no volverá a cargar la página. -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- Los modificadores pueden encadenarse -->
<a v-on:click.stop.prevent="hasEsto"></a>
<!-- solo el modificador -->
<form v-on:submit.prevent></form>
<!-- utilizar el modo de captura al agregar el detector de eventos -->
<!-- es decir, un evento dirigido a un elemento interno se maneja aquí antes de ser maneja
<div v-on:click.capture="hazEsto">...</div>
<!-- solo activa el controlador si event.target es el elemento en sí -->
<!-- es decir, no de un elemento hijo -->
<div v-on:click.self="hazEso">...</div>
El orden es importante cuando se usan modificadores porque el código relevante se genera en el mismo
orden. Por lo tanto, el uso de v-on: click.prevent.self evitará todos los clics mientras que v-on:
click.self.prevent solo evitará clics en el elemento en sí.
Nuevo en 2.1.4+
<!-- El evento de clic se activará como máximo una vez. -->
<a v-on:click.once="hasEsto"></a>
A diferencia de los otros modificadores, que son exclusivos de los eventos DOM nativos, el
modificador .once también se puede usar en eventos personalizados. Si aún no ha leído sobre componentes,
no se preocupe de esto por ahora.
Nuevo in 2.3.0+
Vue también ofrece el modificador .passive, correspondiente a la opción pasiva de addEventListener.
Modificadores de Teclas
Cuando escuchamos eventos de teclado, a menudo necesitamos verificar códigos de teclas comunes. Vue
también permite agregar modificadores clave para v-on cuando se escuchan eventos de teclado:
•.enter
•.tab
•.delete (captura ambas teclas “Delete” y “Backspace”)
•.esc
•.space
•.up
•.down
•.left
•.right
También puede definir alias modificadores de tecla personalizados a través del objeto
global config.keyCodes:
// habilita `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
Nuevo in 2.5.0+
También puede usar directamente cualquier nombre de tecla válido expuesto a través
de KeyboardEvent.key como modificadores convirtiéndolos a kebab-case:
<input @keyup.page-down="onPageDown">
En el ejemplo anterior, solo se llamará al controlador si $event.key === 'PageDown'
Nuevo en 2.1.0+
Puede usar los siguientes modificadores para activar eventos listeners de raton o teclado solo cuando se presiona
la tecla modificadora correspondiente:
•.ctrl
•.alt
•.shift
•.meta
Nota: En los teclados de Macintosh, meta es la tecla de comando (⌘). En los teclados de
Windows, meta es la tecla de Windows (). En los teclados de Sun Microsystems, el meta está
marcado como un diamante sólido (◆). En ciertos teclados, específicamente los teclados y
sucesores de máquinas MIT y Lisp, como el teclado Knight, el teclado space-cadet, el meta está
etiquetado como “META”. En los teclados de Symbolics, el meta está etiquetado como “META”
o “Meta”.
Por ejemplo:
Modificador .exact
Nuevo en 2.5.0+
El modificador .exact permite el control de la combinación exacta de modificadores del sistema necesarios
para desencadenar un evento.
Nuevo en 2.2.0+
•.left
•.right
•.middle
Estos modificadores restringen el controlador a eventos activados por un botón específico del raton.
Es posible que le preocupe que todo este enfoque de escucha de eventos viole las viejas buenas reglas sobre la
“separation of concerns” (“separación de preocupaciones”). Tenga la tranquilidad de que todas las funciones y
expresiones del controlador de Vue están estrictamente vinculadas a ViewModel que esta manejando la vista
actual, no causará ninguna dificultad de mantenimiento. De hecho, hay varios beneficios en el uso de v-on:
1.Es más fácil ubicar las implementaciones de la función de controlador dentro de su código JS al ojear la
plantilla HTML.
2.Una vez que no tenga que adjuntar manualmente eventos listeners en JS, su código de ViewModel puede ser de
lógica pura y libre de DOM. Esto hace que sea más fácil de probar.
3.Cuando se destruye un ViewModel, todos los eventos listeners se eliminan automáticamente. No tiene que
preocuparse por limpiarlo usted mismo.
Uso básico
Para los idiomas que requieren un IME (chino, japonés, coreano, etc.), notará que el v-model no se
actualiza durante la composición del IME. Si también desea atender estas actualizaciones, use un
evento input en su lugar.
Input
Textarea
<div id='example-3'>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})
Radio
<select v-model="selected">
<option disabled value="">Seleccione un elemento</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Seleccionado: {{ selected }}</span>
new Vue({
el: '...',
data: {
selected: ''
}
})
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Seleccionado: {{ selected }}</span>
new Vue({
el: '...',
data: {
selected: 'A',
options: [
Vinculando a Valores
Pero a veces es posible que queramos vincular el valor a una propiedad dinámica en la instancia de Vue. Podemos
usar v-bind para lograr eso. Además, el uso de v-bind nos permite vincular el valor de entrada a valores no
cadena.
Checkbox
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
>
// cuando está marcado:
vm.toggle === 'yes'
// cuando está desmarcado:
vm.toggle === 'no'
Radio
Select
<select v-model="selected">
<!-- objeto literal en línea --> -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
// cuando está seleccionado:
typeof vm.selected // => 'object'
vm.selected.number // => 123
Modificadores
.lazy
Si desea que las entradas del usuario se escriban automáticamente como un número, puede agregar el
modificador number al v-model del elemento:
Esto suele ser útil, porque incluso con type="number", el valor retornado por el elemento HTML siempre es
una cadena de texto. Si el valor no se puede analizar con parseFloat(), se retorna el valor original.
.trim
Si desea que las entradas del usuario se recorten automáticamente, puede agregar el modificador trim al v-
model de su elemento:
<input v-model.trim="msg">
v-model con Componentes
Si aún no está familiarizado con los componentes de Vue, puede omitir esto por ahora.
Los tipos de input nativos de HTML no siempre satisfarán sus necesidades. Afortunadamente, los componentes
de Vue le permiten crear input reutilizables con un comportamiento completamente personalizado. Estos
componentes también funcionan con v-model! Para aprender más, lea acerca de inputs personalizados en la
guía de componentes.
Ejemplo base
Los componentes son instancias reutilizables de Vue con un nombre: en este caso, <button-counter>.
Podemos usar este componente como un elemento personalizado dentro de una instancia de Vue raíz creada
con new Vue:
<div id="components-demo">
<button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })
Dado que los componentes son instancias reutilizables de Vue, aceptan las mismas opciones que new Vue,
como data, computed, watch, methods, y hooks de ciclo de vida. Las únicas excepciones son algunas
opciones específicas de la raíz como el.
Reutilizando Componentes
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
Tenga en cuenta que al hacer clic en los botones, cada uno mantiene su propio count por separado. Esto se debe
a que cada vez que utiliza un componente, se crea una nueva instancia del mismo.
data: {
count: 0
}
En lugar de eso, la opción data de un componente debe ser una función, de modo que cada instancia pueda
mantener una copia independiente del objeto de datos devuelto:
data: function () {
return {
count: 0
}
}
Si Vue no tuviera esta regla, hacer clic en un botón afectaría los datos de todas las demás instancias.
Organización de Componentes
Por ejemplo, puede tener componentes para un encabezado, una barra lateral y un área de contenido, cada uno
de los cuales generalmente contiene otros componentes para enlaces de navegación, publicaciones de blog, etc.
Para usar estos componentes en templates, deben registrarse para que Vue los conozca. Existen dos tipos de
registro de componentes: global y local. Hasta ahora, solo hemos registrado componentes globalmente,
usando Vue.component:
Vue.component('my-component-name', {
Eso es todo lo que necesita saber sobre el registro por ahora, pero una vez que haya terminado de leer esta página
y se sienta cómodo con su contenido, le recomendamos volver más tarde para leer la guía completa de Registro
de Componentes.
Anteriormente, mencionamos la creación de un componente para publicaciones de blog. El problema es que ese
componente no será útil a menos que puedas pasarle datos, como el título y el contenido de la publicación
específica que queremos mostrar. Ahí es donde entran las props.
Las props son atributos personalizados que usted puede registrar en un componente. Cuando se pasa un valor a
un atributo prop, se convierte en una propiedad en esa instancia de componente. Para pasar un título a nuestro
componente de publicación de blog, podemos incluirlo en la lista de props que este componente acepta, usando
la opción props:
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
Un componente puede tener tantas props como se desee, y se puede pasar cualquier valor a cualquier prop de
forma predeterminada. En el template anterior, verá que podemos acceder a este valor en la instancia del
componente, al igual que con data.
Una vez que se registra un prop, puede pasarle datos como un atributo personalizado, de la siguiente manera:
new Vue({
el: '#blog-post-demo',
data: {
posts: [
{ id: 1, title: 'Mi viaje con Vue' },
{ id: 2, title: 'Blogging con Vue' },
{ id: 3, title: 'Por qué Vue es tan divertido?' }
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
></blog-post>
Esto es todo lo que necesita saber sobre propiedades por ahora, pero una vez que haya terminado de leer esta
página y se sienta cómodo con su contenido, le recomendamos volver más tarde para leer la guía completa
de Propiedades.
Sin embargo, si intenta esto en su plantilla, Vue mostrará un error, explicando que cada componente debe tener
un solo elemento raíz. Puede corregir este error envolviendo la plantilla en un elemento principal de la siguiente
manera:
<div class="blog-post">
<h3>{{ title }}</h3>
<div v-html="content"></div>
</div>
A medida que nuestro componente crezca, es probable que no solo necesitemos el título y el contenido de una
publicación, sino también la fecha de publicación, los comentarios y más. Definir una propiedad para cada pieza
de información relacionada podría volverse muy molesto:
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
v-bind:content="post.content"
Por lo tanto, este podría ser un buen momento para refactorizar el componente <blog-post> para que acepte
una única propiedad post:
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
})
El ejemplo anterior y algunos que veremos más adelante, utilizan Plantillas de cadena de texto de
JavaScript para hacer que las plantillas multilínea sean más legibles. Internet Explorer (IE) no las admite, por
lo tanto, si debe ser compatible con IE y no está transpilando (por ejemplo, con Babel o TypeScript),
usa escapes de nueva línea en su lugar
Ahora, cada vez que se agreguen nuevas propiedadaes al objeto post, estarán automáticamente disponible
dentro de <blog-post>.
A medida que desarrollamos nuestro componente <blog-post>, es posible que algunas funciones requieran la
comunicación hacia el componente padre. Por ejemplo, podemos decidir incluir una función de accesibilidad
para ampliar el texto de las publicaciones del blog, dejando el resto de la página en su tamaño por defecto:
new Vue({
el: '#blog-posts-events-demo',
data: {
posts: [/* ... */],
postFontSize: 1
}
})
<div id="blog-posts-events-demo">
<div :style="{ fontSize: postFontSize + 'em' }">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
</div>
</div>
Ahora agreguemos un botón para ampliar el texto justo antes del contenido de cada publicación:
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button>
Agrandar texto
</button>
<div v-html="post.content"></div>
</div>
`
})
<button>
Agrandar texto
</button>
Cuando hacemos clic en el botón, debemos comunicar al componente padre que debe agrandar el texto de todas
las publicaciones. Afortunadamente, las instancias de Vue proporcionan un sistema de eventos personalizados
para resolver este problema. Para emitir un evento a los padres, podemos llamar al método $emit, pasando el
nombre del evento:
<button v-on:click="$emit('enlarge-text')">
Agrandar texto
</button>
Luego, en nuestro blog post, podemos escuchar este evento con v-on, tal como lo haríamos con un evento DOM
nativo:
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
A veces es útil emitir un valor específico con un evento. Por ejemplo, podemos querer que el
componente <blog-post> se encargue de cuánto agrandar el texto. En esos casos, podemos usar el segundo
parámetro de $emit para proporcionar este valor:
Luego, cuando escuchamos el evento en el componente padre, podemos acceder al valor del evento emitido
con $event:
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>
<blog-post
...
v-on:enlarge-text="onEnlargeText"
></blog-post>
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
Usando v-model en Componentes
Los eventos personalizados también se pueden usar para crear inputs personalizados que funcionan con v-
model. Recuerde que:
<input v-model="searchText">
<input
v-bind:value="searchText"
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
Para que esto realmente funcione, el <input> dentro del componente debe:
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
<custom-input v-model="searchText"></custom-input>
Por ahora, eso es todo lo que necesita saber sobre los eventos de componentes personalizados, pero una vez que
haya terminado de leer esta página y se sienta cómodo con su contenido, le recomendamos volver más tarde para
leer la guía completa sobre Eventos Personalizados.
Al igual que con los elementos HTML, a menudo es útil poder pasar contenido a un componente, como este:
<alert-box>
Algo ha ocurrido mal.
</alert-box>
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
Como verá más arriba, solo agregamos la ranura a la que queremos que el contenido vaya – y eso es todo. Hemos
terminado!
Eso es todo lo que necesita saber acerca de slots por ahora, pero una vez que haya terminado de leer esta página
y se sienta cómodo con su contenido, le recomendamos que regrese más tarde para leer la guía completa
de Slots.
Componentes dinámicos
A veces, es útil cambiar dinámicamente entre componentes, como en una interfaz con pestañas:
Componente de Inicio
Vea este fiddle para experimentar con el código completo, o esta versión para un ejemplo de enlace o binding al
objeto de opciones de un componente, en lugar de su nombre registrado.
Eso es todo lo que necesita saber sobre los componentes dinámicos por ahora, pero una vez que haya terminado
de leer esta página y se sienta cómodo con su contenido, le recomendamos volver más tarde para leer la guía
completa sobre Componentes Dinámicos y Asíncronos.
Esto conducirá a problemas cuando se utilizan componentes con elementos que tienen tales restricciones. Por
ejemplo:
<table>
<blog-post-row></blog-post-row>
</table>
El componente personalizado <blog-post-row> se colocará como contenido no válido, lo que provocará
errores en el resultado final. Afortunadamente, el atributo especial is ofrece una solución alternativa:
<table>
<tr is="blog-post-row"></tr>
</table>
Debe tenerse en cuenta que esta limitación no se aplica si está utilizando plantillas de cadenas de texto de
una de las siguientes fuentes:
Una vez que se sienta cómodo con el conocimiento que acaba de digerir, le recomendamos que regrese para leer
la guía completa de Componentes Dinámicos y Asíncronos, así como las otras páginas en la
sección Componentes en Profundidad de la barra lateral.