Afegim propietats
Les props (propietats) són els paràmetres que li passem al component. Com hem vist, els components estan totalment aïllats. Si tenim un component <targeta-usuari>, per defecte no sap qui és l'usuari ni quines dades té. Per solucionar-ho, Vue utilitza un sistema de comunicació anomenat One-Way Data Flow (Flux de dades unidireccional): les dades sempre viatgen de dalt a baix, del component pare (l'aplicació principal) cap al component fill.
Com declarar i utilitzar Props
Dins de l'arxiu del nostre component (ex: TargetaUsuari.js), hem d'avisar a Vue que estem esperant rebre dades des de l'exterior. Ho fem afegint la propietat props. Podem declarar-les com un simple Array de textos, o millor encara, com un Objecte per validar quin tipus de dada esperem (String, Number, Boolean, Object...). Un cop declarada, la prop s'utilitza exactament igual que qualsevol variable de data().
// TargetaUsuari.js
export default {
name: 'TargetaUsuari',
// Manera recomanada: Objecte amb validació de tipus
props: {
nom: String,
edat: Number,
esPremium: Boolean
},
template: `
<div class="targeta" :class="{ 'fons-daurat': esPremium }">
<h3>{{ nom }}</h3>
<p>Edat: {{ edat }} anys</p>
<p v-if="esPremium">⭐ Usuari VIP</p>
</div>
`
}
Com enviar les dades?
Ara, a l'HTML de la nostra aplicació principal, podem utilitzar la nostra nova etiqueta i passar-li les dades com si fossin atributs HTML normals (com el src d'una <img> o el href d'un <a>). Aquí tenim dos escenaris: Dades estàtiques i Dades dinàmiques.
A. Passar text estàtic
Si només volem passar una cadena de text fixa, ho escrivim tal qual:
<targeta-usuari nom="Anna Garcia"></targeta-usuari>
B. Passar dades dinàmiques o números (Utilitzant v-bind o :)
Això és molt important: si volem passar una variable de l'aplicació, o un tipus de dada que no sigui text (com un número o un booleà), hem d'utilitzar els dos punts : davant del nom de la prop. Això li diu a Vue: "Ei, no passis la paraula literal, avalua el contingut de les cometes com a JavaScript".
<targeta-usuari nom="Marta" edat="25" esPremium="true"></targeta-usuari>
<targeta-usuari nom="Marta" :edat="25" :esPremium="true"></targeta-usuari>
<targeta-usuari :nom="usuariActual.nom" :edat="usuariActual.edat"></targeta-usuari>
El format (camelCase vs kebab-case)
Aquest és un dels errors on tot desenvolupador primerenc s'encalla més. El llenguatge HTML és case-insensitive (no distingeix entre majúscules i minúscules). Per tant, si al teu component JavaScript crees una prop anomenada nomUsuari (camelCase), a l'HTML l'has d'escriure separada per guions nom-usuari (kebab-case). Vue ja s'encarrega de fer la traducció internament.
| On ho escrius | Format requerit | Exemple |
| JavaScript (Definició) | camelCase | props: { colorFons: String } |
| HTML (Ús de l'etiqueta) | kebab-case | <targeta :color-fons="'red'"> |
Exemple
La veritable potència de les props es demostra quan iterem sobre una llista de dades provinent d'una API (o del backend de CodeIgniter) i generem un component per a cada element.
<div id="app">
<h2>Llistat del Sistema</h2>
<targeta-usuari
v-for="usuari in llistaUsuaris"
:key="usuari.id"
:nom="usuari.nom"
:edat="usuari.edat"
:es-premium="usuari.vip">
</targeta-usuari>
</div>
⚠️ Advertència (Mutabilitat):
Cal recalcar que les
propssón de només lectura. Un component fill mai ha d'intentar modificar una prop directament (per exemple,this.edat = 30dins del fill generarà un error a la consola). Si el fill necessita canviar una dada, ha d'avisar al pare perquè ho faci.
Caracteristiques de la propietats
Quan treballem en equip (o quan revisem el nostre propi codi mesos després), definir estrictament què accepta cada component ens estalvia hores de depuració. A Vue, quan definim les props com un Objecte en lloc d'un simple Array, activem el sistema de validació de propietats. Si l'aplicació principal intenta passar una dada incorrecta a un component, la web no es trencarà de cop, però Vue ens mostrarà un avís taronja molt descriptiu a la consola del navegador indicant l'error.
type (tipus de dada)
Garanteix que la dada que rebem és exactament del tipus que esperem. Si esperem un número per fer un càlcul matemàtic i ens passen un text, Vue ens avisarà.
-
Tipus natius permesos:
String,Number,Boolean,Array,Object,Date,Function,Symbol. -
Podem permetre més d'un tipus passant un Array de tipus.
props: {
// Només accepta text
nom: {
type: String
},
// Accepta text O un número (ex: un ID d'usuari)
idUsuari: {
type: [String, Number]
}
}
required (Obligatorietat)
Per defecte, totes les props a Vue són opcionals. Si el nostre component no pot funcionar sense una dada específica (per exemple, la imatge de perfil en una <targeta-usuari>), hem de fer-la obligatòria.
props: {
correuElectronic: {
type: String,
required: true // Si l'HTML no li passa aquest atribut, Vue donarà un error a la consola
}
}
default (Valor per defecte)
Si una propietat no és obligatòria (required: false) i l'usuari no ens la passa des de l'HTML, el seu valor serà undefined. Amb default, podem establir un valor de rescat.
⚠️ Que passa amb els Objectes i Arrays :
Si el valor per defecte és un tipus primitiu (Text, Número o Booleà), es posa directament. Però si el valor per defecte és un
Arrayo unObject, hem d'utilitzar una funció que el retorni. Si no ho fem així, tots els components que es dibuixin a la pantalla compartiran exactament el mateix Array a la memòria i es modificaran els uns als altres.
props: {
// Valor primitiu (Senzill)
colorTema: {
type: String,
default: 'blau'
},
// ⚠️ Array o Objecte (Requereix una funció de fàbrica)
llistaAmics: {
type: Array,
default() {
return []; // Retorna un Array buit i independent per a cada component
}
}
}
validator (Validació personalitzada)
És la funcionalitat més avançada. Permet escriure una funció de JavaScript pròpia que rebrà el valor que intenta entrar al component. Si la funció retorna true, el valor s'accepta; si retorna false, es rebutja. És ideal per a components de disseny, com ara botons, on només vols permetre uns colors o mides concretes.
props: {
estatNotificacio: {
type: String,
// El valor introduït ha de coincidir amb un d'aquests tres
validator(valor) {
return ['exit', 'alerta', 'error'].includes(valor);
}
}
}
Exemple
Així és com es veuria l'objecte props en un component complet que reuneix totes aquestes validacions de forma professional:
export default {
name: 'BotoAccio',
props: {
// Obligatori i ha de ser text
titol: {
type: String,
required: true
},
// Opcional, per defecte 0
copsClicat: {
type: Number,
default: 0
},
// Opcional, però si es posa, ha de ser d'una llista concreta
mida: {
type: String,
default: 'mitjana',
validator(valor) {
return ['petita', 'mitjana', 'gran'].includes(valor);
}
},
// Opcional, valor per defecte és un Objecte (funció)
configuracioAvançada: {
type: Object,
default() {
return { animat: true, ombra: false };
}
}
},
template: `
<button class="boto" :class="mida">
{{ titol }} (Clics: {{ copsClicat }})
</button>
`
}