# Guía de Estilo

Esta es la guía de estilo oficial para el código específico de Vue. Si utiliza Vue en un proyecto, es una excelente referencia para evitar errores, “bikeshedding” y antipatrones. Sin embargo, no creemos que ninguna guía de estilo sea ideal para todos los equipos o proyectos, por lo que las desviaciones conscientes se fomentan en función de la experiencia pasada, la tecnología acumulada y los valores personales.

También evitamos las sugerencias sobre JavaScript o HTML en general. No nos importa si utiliza punto y coma o comas finales. No nos importa si su HTML utiliza comillas simples o comillas dobles para los valores de los atributos. Sin embargo, algunas excepciones existirán cuando descubramos que un patrón particular es útil en el contexto de Vue.

Finalmente, hemos dividido las reglas en cuatro categorías:

# Categorías de Reglas

# Prioridad A: Esencial

Estas reglas ayudan a prevenir errores, así que apréndalas y cumpla con ellas a toda costa. Pueden existir excepciones, pero deben ser muy raras y sólo las deben realizar aquellas personas con conocimientos de JavaScript y Vue.

# Prioridad B: Muy recomendable

Se ha descubierto que estas reglas mejoran la legibilidad y/o la experiencia del desarrollador en la mayoría de los proyectos. Su código aún se ejecutará si no las respeta, pero estas excepciones deben ser raras y estar bien justificadas.

# Prioridad C: Recomendado

Donde existen opciones múltiples e igualmente buenas, se puede hacer una elección arbitraria para garantizar la coherencia. En estas reglas, describimos cada opción aceptable y sugerimos una opción predeterminada. Eso significa que puede sentirse libre de hacer una elección diferente en su propia base de código, siempre que sea coherente y tenga una buena razón para ello. Por favor, justifique su elección! Al adaptarse al estándar de la comunidad, usted:

  1. Entrena su cerebro para analizar más fácilmente la mayoría del código de comunidad que encuentre
  2. Será capaz de copiar y pegar la mayoría de los ejemplos de código de comunidad sin modificación
  3. A menudo descubrirá que los nuevos empleados ya están amoldadas a su estilo de codificación preferido, al menos en lo que respecta a Vue

# Prioridad D: Utilizar con precaución

Algunas características de Vue existen para adaptarse a casos excepcionales o migraciones menos “agresivas” desde una base de código heredada. Sin embargo, cuando se usan en exceso, pueden hacer que su código sea más difícil de mantener o incluso convertirse en una fuente de errores. Estas reglas arrojan luz sobre las características potencialmente riesgosas, y describen cuándo y por qué deberían evitarse.

# Reglas de prioridad A: Esencial (prevención de errores)

# Nombres de componentes de varias palabras esencial

Los nombres de los componentes siempre deben ser de varias palabras, a excepción de los componentes raíz de la App y los componentes integrados proporcionados por Vue, tales como <transition> or <component>.

Esto evita conflictos (opens new window) con elementos HTML existentes y futuros, ya que todos los elementos HTML son una sola palabra.

Incorrecto

app.component('todo', {
  // ...
})
1
2
3
export default {
  name: 'Todo',
  // ...
}
1
2
3
4

Correcto

app.component('todo-item', {
  // ...
})
1
2
3
export default {
  name: 'TodoItem',
  // ...
}
1
2
3
4

# Definiciones de Props esencial

Las definiciones de Props deben ser lo mas detalladas posible.

En el código “commiteado”, las definiciones de props siempre deben ser lo más detalladas posible, especificando al menos su(s) tipo(s).

Explicación Detallada

Las definiciones detalladas de props tienen dos ventajas:

  • Documentan la API del componente, de modo que es fácil ver cómo se debe utilizar el componente.
  • En desarrollo, Vue le advertirá si algún componente se proporciona con props formateados incorrectamente, ayudándole a detectar posibles fuentes de error.

Incorrecto

// Esto esta BIEN solo cuando se prototipa
props: ['status']
1
2

Correcto

props: {
  status: String
}
1
2
3
// ¡aún mejor!
props: {
  status: {
    type: String,
    required: true,

    validator: value => {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].includes(value)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Key + v-for esencial

Siempre utiliza key con v-for.

key con v-for es siempre requerido en componentes, para mantener el estado del componente interno en el subárbol. Sin embargo, incluso para los elementos, es una buena práctica mantener un comportamiento predecible, como constancia del objeto (opens new window) en las animaciones.

Explicación Detallada

Digamos que tiene una lista de "ToDos":

data() {
  return {
    todos: [
      {
        id: 1,
        text: 'Aprender a utilizar v-for'
      },
      {
        id: 2,
        text: 'Aprender a utilizar key'
      }
    ]
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Luego los ordena alfabéticamente. Al actualizar el DOM, Vue optimizará la renderización para realizar las mutaciones de DOM más efectivas en lo posible. Eso podría significar eliminar el primer elemento del "ToDo" y luego agregarlo nuevamente al final de la lista.

El problema es que hay casos en los que es importante no eliminar elementos que permanecerán en el DOM. Por ejemplo, puede utilizar <transition-group> para animar el orden de las listas, o mantener el foco si el elemento renderizado es <input>. En estos casos, agregar una clave única para cada elemento (por ejemplo, :key="todo.id") le indicará a Vue cómo comportarse de manera más predecible.

En nuestra experiencia, es mejor agregar siempre una clave única, para que usted y su equipo simplemente nunca tengan que preocuparse por estos casos extremos. Luego, en los raros escenarios de rendimiento crítico donde la constancia del objeto no es necesaria, puede hacer una excepción consciente.

Incorrecto

<ul>
  <li v-for="todo in todos">
    {{ todo.text }}
  </li>
</ul>
1
2
3
4
5

Correcto

<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>
1
2
3
4
5
6
7
8

# Evitar v-if con v-for esencial

Nunca utilice v-if en el mismo elemento que v-for.

Hay dos casos comunes en los que esto puede ser tentador:

  • Para filtrar elementos en una lista (por ejemplo, v-for="user in users" v-if="user.isActive"). En estos casos, reemplace users con una nueva propiedad calculada que devuelva su lista filtrada (por ejemplo activeUsers).

  • Para evitar renderizar una lista si debe estar oculta (por ejemplo, v-for="user in users" v-if="shouldShowUsers"). En estos casos, mueva el v-if a un elemento contenedor (por ejemplo,ul, ol).

Explicación Detallada

Cuando Vue procesa directivas, v-if tiene mayor prioridad que v-for, entonces esta plantilla:

<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
1
2
3
4
5
6
7
8
9

Arrojará un error, porque la directiva v-if se evaluará primero y el variable de iteración user no existe en este momento.

Este puede ser corregido mediante iterar sobre una propiedad computada en su lugar, como esto:

computed: {
  activeUsers() {
    return this.users.filter(user => user.isActive)
  }
}
1
2
3
4
5
<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
1
2
3
4
5
6
7
8

Alternativamente, podemos utilizar una etiqueta <template> con v-for para envolver el elemento <li>:

<ul>
  <template v-for="user in users" :key="user.id">
    <li v-if="user.isActive">
      {{ user.name }}
    </li>
  </template>
</ul>
1
2
3
4
5
6
7

Incorrecto

<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
1
2
3
4
5
6
7
8
9

Correcto

<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
1
2
3
4
5
6
7
8
<ul>
  <template v-for="user in users" :key="user.id">
    <li v-if="user.isActive">
      {{ user.name }}
    </li>
  </template>
</ul>
1
2
3
4
5
6
7

# Alcance de Estilos de Componentes esencial

Para las aplicaciones, los estilos, en un componente App de nivel superior y en los componentes de "layout" pueden ser globales, pero todos los demás componentes siempre deben poseer sus propios alcances (be scoped).

Esto es relevante sólo a componentes de un solo archivo. No requiere que se utilice el atributo scoped (opens new window). El "alcance" podría implementarse a través de módulos CSS (opens new window), una estrategia basada en clases como BEM (opens new window), ú otra biblioteca/convención.

Para las bibliotecas de componentes, sin embargo, se debería implementar una estrategia basada en clases en vez de usar el atributo scoped.

Esto hace que sea más fácil sobreescribir los estilos internos, con nombres de clase legibles que no tienen una especificidad demasiado alta, y menos probable que generen conflictos.

Explicación Detallada

Si está desarrollando un proyecto grande, trabajando con otros desarrolladores o, a veces, incluye HTML / CSS de terceros (por ejemplo, de Auth0), el alcance consistente (consistent scoping) garantizará que sus estilos solo se apliquen a los componentes para los que están diseñados.

Más allá del atributo scoped, el uso de nombres de clase únicos puede ayudar a garantizar que el CSS de terceros no se aplique a su propio HTML. Por ejemplo, muchos proyectos usan los nombres de las clases button,btn o icon, por lo que incluso si no usan una estrategia como BEM, agregan un prefijo específico de la aplicación y / o componente específico (por ejemplo,ButtonClose-icon) puede proporcionar cierta protección.

Incorrecto

<template>
  <button class="btn btn-close">×</button>
</template>

<style>
.btn-close {
  background-color: red;
}
</style>
1
2
3
4
5
6
7
8
9

Correcto

<template>
  <button class="button button-close">×</button>
</template>

<!-- Utilizando el atributo `scoped` -->
<style scoped>
.button {
  border: none;
  border-radius: 2px;
}

.button-close {
  background-color: red;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
  <button :class="[$style.button, $style.buttonClose]">×</button>
</template>

<!-- Utilizando módulos CSS -->
<style module>
.button {
  border: none;
  border-radius: 2px;
}

.buttonClose {
  background-color: red;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
  <button class="c-Button c-Button--close">×</button>
</template>

<!-- Utilizando la convención BEM -->
<style>
.c-Button {
  border: none;
  border-radius: 2px;
}

.c-Button--close {
  background-color: red;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Nombres de propiedades privadas esencial

Utiliza alcance de módulo para mantener funciones privadas inaccesibles desde fuera. Si eso no es posible, siempre utilice el prefijo $_ para propiedades privadas personalizadas en un plugin, mixin, etc. que no debería considerarse como API pública. Luego para evitar conflictos con código por otros autores, también incluya un alcance nombrado (p. ej. $_yourPluginName_).

Explicación Detallada

Vue utiliza el prefijo _ para definir sus propias propiedades privadas, entonces, utilizar el mismo prefijo (ej. _update) puede causar que una propiedad privada sea sobreescrita. Incluso si usted verifica y Vue no esta haciendo uso de dicho nombre, no hay garantía de que este conflicto no surja en una versión futura.

En cuanto al prefijo $, su propósito en el ecosistema de Vue es identificar las propiedades especiales de instancia que están expuestas al usuario, por lo tanto, utilizarlo para propiedades privadas no sería apropiado.

En su lugar, recomendamos combinar ambos prefijos en $_, como una convención para propiedades privadas definidas por el usuario para que no haya conflicto con Vue.

Incorrecto

const myGreatMixin = {
  // ...
  methods: {
    update() {
      // ...
    }
  }
}
1
2
3
4
5
6
7
8
const myGreatMixin = {
  // ...
  methods: {
    _update() {
      // ...
    }
  }
}
1
2
3
4
5
6
7
8
const myGreatMixin = {
  // ...
  methods: {
    $update() {
      // ...
    }
  }
}
1
2
3
4
5
6
7
8
const myGreatMixin = {
  // ...
  methods: {
    $_update() {
      // ...
    }
  }
}
1
2
3
4
5
6
7
8

Correcto

const myGreatMixin = {
  // ...
  methods: {
    $_myGreatMixin_update() {
      // ...
    }
  }
}
1
2
3
4
5
6
7
8
// ¡aún mejor!
const myGreatMixin = {
  // ...
  methods: {
    publicMethod() {
      // ...
      myPrivateFunction()
    }
  }
}

function myPrivateFunction() {
  // ...
}

export default myGreatMixin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Reglas de prioridad B: Altamente Recomendadas (Mejorar la legibilidad)

# Archivos de componentes altamente recomendada

Siempre que un sistema de compilación pueda concatenar archivos, cada componente debería estar en su propio archivo.

Esto lo ayudará a usted a encontrar de una manera más rápida un componente cuando precise editarlo o verificar como se utiliza.

Incorrecto

app.component('TodoList', {
  // ...
})

app.component('TodoItem', {
  // ...
})
1
2
3
4
5
6
7

Correcto

components/
|- TodoList.js
|- TodoItem.js
1
2
3
components/
|- TodoList.vue
|- TodoItem.vue
1
2
3

# Notación de nombres de componentes de un solo archivo altamente recomendado

Los nombres de los componentes de un solo archivo deben ser siempre PascalCase o siempre kebab-case.

El autocompletado de los editores de código funciona mejor cuando se utiliza PascalCase, ya que esta es consistente con la forma en que referenciamos componentes en JS(X) y plantillas, dónde sea posible. Sin embargo, nombres de archivos mixtos pueden crear problemas en sistemas de archivos insensibles a las mayúsculas y minúsculas, es por esto que utilizar kebab-case es perfectamente aceptable.

Incorrecto

components/
|- mycomponent.vue
1
2
components/
|- myComponent.vue
1
2

Correcto

components/
|- MyComponent.vue
1
2
components/
|- my-component.vue
1
2

# Nombre de componentes base altamente recomendado

Los componentes base (también conocidos como componentes de presentación, "tontos", o puros) que aplican estilos y convenciones específicas de la aplicación, deben comenzar con un prefijo específico, tal como Base, App o V.

Explicación Detallada

Estos componentes son la base para la definición de estilos y comportamientos consistentes en la aplicación. Estos solamente deben contener:

  • elementos HTML,
  • otros componentes base, y
  • componentes de interfaz de usuario de terceros.

Pero, nunca deben contener estado global (p. ej. proviene de una store Vuex).

Sus nombres generalmente incluyen el nombre del elemento que envuelven (por ejemplo BaseButton, BaseTable), a menos que no exista un elemento para su propósito específico (por ejemplo BaseIcon). Si usted construye componentes similares para un contexto más específico, casi siempre consumirán estos componentes (por ejemplo BaseButton podría ser consumido en ButtonSubmit).

Algunas ventajas de esta convención:

  • Cuando están organizados alfabéticamente en los editores, los componentes base de su aplicación serán listados todos juntos, volviéndose más fácil de identificar.

  • Dado que los nombres de los componentes siempre deben ser multi-palabras, esta convención impide tener que elegir un prefijo arbitrario para envoltorios de componente simples (por ejemplo MyButton, VueButton).

  • Dado que estos componentes se utilizan con frecuencia, es posible que simplemente desee hacerlos globales en vez de importarlos en todos lados. Un prefijo hace esto posible con Webpack:

    const requireComponent = require.context("./src", true, /Base[A-Z]\w+\.(vue|js)$/)
    requireComponent.keys().forEach(function (fileName) {
      let baseComponentConfig = requireComponent(fileName)
      baseComponentConfig = baseComponentConfig.default || baseComponentConfig
      const baseComponentName = baseComponentConfig.name || (
        fileName
          .replace(/^.+\//, '')
          .replace(/\.\w+$/, '')
      )
      app.component(baseComponentName, baseComponentConfig)
    })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

Incorrecto

components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
1
2
3
4

Correcto

components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
1
2
3
4
components/
|- AppButton.vue
|- AppTable.vue
|- AppIcon.vue
1
2
3
4
components/
|- VButton.vue
|- VTable.vue
|- VIcon.vue
1
2
3
4

# Nombres de componentes de instancia única altamente recomendado

Componentes que deben tener solamente una única instancia activa deben comenzar con el prefijo The, para denotar que solo puede haber una.

Esto no quiere decir que el componente solamente se utiliza en una única página, sino que solamente será utilizado una vez por página. Este tipo de componente nunca aceptan props, dado que son específicas para la aplicación, no del contexto de la misma. Si usted encuentra la necesidad de añadir props, puede ser un buen indicio de que de hecho se trata de un componente reusable que solamente se utiliza una vez por página, por ahora.

Incorrecto

components/
|- Heading.vue
|- MySidebar.vue
1
2
3

Correcto

components/
|- TheHeading.vue
|- TheSidebar.vue
1
2
3

# Nombres de componentes fuertemente acoplados altamente recomendado

Los componentes hijo que están fuertemente acoplados a su padre deben incluir el nombre del componente padre como prefijo.

Si un componente solo tiene sentido en el contetxo de un componente padre, dicha relación debe ser evidente en su nombre. Dado que usualmente los editores organizan los archivos alfabéticamente, esto también deja ambos archivos cerca visualmente.

Explicación Detallada

Usted puede verse tentado a resolver este problema colocando los componentes hijo en directorios nombrados como su componente padre. Por ejemplo:

components/
|- TodoList/
   |- Item/
      |- index.vue
      |- Button.vue
   |- index.vue
1
2
3
4
5
6

o:

components/
|- TodoList/
   |- Item/
      |- Button.vue
   |- Item.vue
|- TodoList.vue
1
2
3
4
5
6

Esto no es recomendado, ya que resulta en:

  • Muchos archivos con nombres similares, haciendo difícil cambiar entre archivos en un editor de código.
  • Muchos subdirectorios anidados, lo cual incrementa el tiempo que toma para navegar componentes en la barra lateral de un editor.

Incorrecto

components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
1
2
3
4
components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue
1
2
3

Correcto

components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
1
2
3
4
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue
1
2
3

# Orden de las palabras en el nombre de los componentes altamente recomendado

Los nombres de los componentes deben comenzar con la palabra de más alto nivel (muchas veces la más general) y terminar con palabras descriptivas.

Explicación Detallada

Usted se debe estar preguntando:

"¿Por qué forzar un lenguaje menos natural al nombrar componentes?"

En inglés natural, adjetivos y otros descriptores aparecen típicamente antes de los sustantivos, mientras que excepciones requieren conectores. Por ejemplo:

  • Coffee with milk
  • Soup of the day
  • Visitor to the museum

Usted puede definitivamente incluir estos conectores en el nombre de los componentes si así lo desea, pero el orden de las palabras sigue siendo importante.

También observe que lo que es considerado "de más alto nivel" será contextual a su aplicación. Por ejemplo, imagine una aplicación con un formulario de búsqueda. Este puede incluir componentes como esto:

components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue
1
2
3
4
5
6
7

Como puede ver, es muy difícil ver que componentes son específicas para el formulario de búsqueda. Ahora, renombremos los componentes de acuerdo a la regla:

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputExcludeGlob.vue
|- SearchInputQuery.vue
|- SettingsCheckboxLaunchOnStartup.vue
|- SettingsCheckboxTerms.vue
1
2
3
4
5
6
7

Ya que típicamente los editores organizan los archivos alfabéticamente, todos los componentes que se relacionan quedan evidentes por el propio nombre.

Usted puede verse tentado a resolver este problema de una forma diferente, anidando todos los componentes del formulario de búsqueda bajo un directorio llamado "search", y todos los componentes de configuración bajo otro directorio llamado "settings". Solo recomendamos este enfoque en aplicaciones de gran porte (por ejemplo, con más de 100 componentes), por las siguientes razones:

  • Generalmente lleva más tiempo navegador a través de subdirectorios anidados que recorrer un simple directorio components.
  • Conflictos de nombres (por ejemplo, múltiples componentes ButtonDelete.vue) dificultan la navegación rápida a un componente específico en un editor de código.
  • La refactorización se vuelve más difícil, ya que buscar-y-sustituir no siempre será suficiente para actualizar las referencias relativas al componente movido.

Incorrecto

components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue
1
2
3
4
5
6
7

Correcto

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
1
2
3
4
5
6
7

# Componentes con cierre automático altamente recomendado

Componentes sin contenido deben cerrarse automáticamenete en componentes de un solo archivo, plantillas de cadena de caracteres, y JSX - pero nunca en plantillas del DOM.

Los componentes que se cierran automáticamente no solo comunican que no tienen contenido, sino que garantizan que no deben tener contenido. Es la diferencia entre una página en blanco en un libro y una con el texto "Está página fue intencionalmente dejada en blanco". También, su código es más limpio sin la etiqueta de cerrado innecesaria.

Desafortunadamente, HTML no permite que los elementos personalizados se cierren automáticamente - sólo los elementos sin contenidos (void) oficiales (opens new window). Es por eso que esta estrategia solo es posible cuando el compilador de plantillas de Vue pueda acceder la plantilla antes del DOM, luego sirva HTML compatible con la especifiación de DOM.

Incorrecto

<!-- En componentes de un solo archivo, plantillas basadas en cadena de caracteres, y JSX -->
<MyComponent></MyComponent>
1
2
<!-- en plantillas del DOM -->
<my-component/>
1
2

Correcto

<!-- En componentes de un solo archivo, plantillas basadas en cadena de caracteres, y JSX -->
<MyComponent/>
1
2
<!-- en plantillas del DOM -->
<my-component></my-component>
1
2

# Notación de nombres de componentes en plantillas altamente recomendado

En la mayoría de los proyectos, los nombres de los componentes deben ser siempre PascalCase en componentes de un solo archivo y plantillas basadas en cadena de caracteres - pero kebab-case en plantillas del DOM.

PascalCase tiene algunas ventajas sobre kebab-case:

  • Editores pueden autocompletar nombres de componentes en plantillas, ya que en JavaScript también se utiliza PascalCase.
  • <MyComponent> es más distintivo visualmente que un elemento HTML de un solo palabra que <my-component>, porque hay dos caracteres distintos (las dos mayúsculas), en lugar de solo uno (el guión).
  • Si usted utiliza elementos personalizados que no son de Vue en sus plantillas, como un componente web, PascalCase asegura que sus componentes Vue se mantendrán distinguibles visualmente.

Desafortunadamente, como HTML es insensible a las mayúsculas y minúsculas, plantillas del DOM deben utilizar kebab-case.

También tenga en cuenta que si usted ya ha invertido fuertemente en kebab-case, la consistencia con las convenciones de HTML y la posibilidad de utilizar ese mismo enfoque en todos sus proyectos puede ser más importante que las ventajas mencionadas anteriormente. En dichos casos, utilizar kebab-case en todos lados también es aceptable.

Incorrecto

<!-- En componentes de un solo archivo, plantillas basadas en cadena de caracteres -->
<mycomponent/>
1
2
<!-- En componentes de un solo archivo, plantillas basadas en cadena de caracteres -->
<myComponent/>
1
2
<!-- En plantillas del DOM -->
<MyComponent></MyComponent>
1
2

Correcto

<!-- En componentes de un solo archivo, plantillas basadas en cadena de caracteres -->
<MyComponent/>
1
2
<!-- En plantillas del DOM -->
<my-component></my-component>
1
2

OR

<!-- En todos lados -->
<my-component></my-component>
1
2

# Notación de nombres de componentes en JS/JSX altamente recomendado

Los nombres de los componentes en JS/JSX siempre deben ser PascalCase, aunque pueden ser kebab-case dentro de cadenas de caracteres para aplicaciones más simples, que solo utilizan registro global de componentes a través de app.component.

Explicación Detallada

En JavaScript, PascalCase es la convención para clases y constructores de prototipo - esencialmente, cualquier cosa que pueda tener instancias diferentes. Los componentes de Vue también tienen instancias, así que tiene sentido utilizar PascalCase. Como un beneficio agregado, utilizar PascalCase en JSX (y plantillas) les permite a los lectores del código distinguen de una manera más fácil entre componentes y elementos HTML.

Sin embargo, para aplicaciones que solo utilizen definiciones globales de componentes a través de app.component, recomendamos utilizar kebab-case en su lugar. Las razones son las siguientes:

  • Es raro que los componentes globales sean referenciados en JavaScript, entonces adoptar una convención para Javascript no tiene sentido.
  • Estas aplicaciones siempre incluyen muchas plantillas del DOM donde kebab-case debe ser utilizada.

Incorrecto

app.component('myComponent', {
  // ...
})
1
2
3
import myComponent from './MyComponent.vue'
1
export default {
  name: 'myComponent',
  // ...
}
1
2
3
4
export default {
  name: 'my-component',
  // ...
}
1
2
3
4

Correcto

app.component('MyComponent', {
  // ...
})
1
2
3
app.component('my-component', {
  // ...
})
1
2
3
import MyComponent from './MyComponent.vue'
1
export default {
  name: 'MyComponent',
  // ...
}
1
2
3
4

# Componentes con nombres completos altamente recomendado

Nombres de componentes deben tener palabras completas, en vez de abreviaciones.

El autocompletado automático en los editores hace que el costo de escribir nombres largos muy bajo, mientras que la claridad que estos proveen es invaluable. En particular, las abreviaciones poco comunes debe ser evitadas.

Incorrecto

components/
|- SdSettings.vue
|- UProfOpts.vue
1
2
3

Correcto

components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
1
2
3

# Notación de nombres de props altamente recomendado

Los nombres de props siempre deben utilizar camelCase al declararse, pero kebab-case en plantillas y JSX.

Simplemente estamos siguiendo las convenciones de cada lenguaje. En Javascript, camelCase es más natural, mientras que HTML, kebab-case lo es.

Incorrecto

props: {
  'greeting-text': String
}
1
2
3
<WelcomeMessage greetingText="hi"/>
1

Correcto

props: {
  greetingText: String
}
1
2
3
<WelcomeMessage greeting-text="hi"/>
1

# Elementos con múltiples atributos altamente recomendado

Elementos con múltiples atributos deben ocupar múltiples líneas, con un atributo por línea.

En Javascript, dividir objetos que poseen múltiples propiedades en varias líneas es considerado una buena práctica, porque es mucho más fácil de leer. Nuestras plantillas y JSX merecen la misma consideración.

Incorrecto

<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
1
<MyComponent foo="a" bar="b" baz="c"/>
1

Correcto

<img
  src="https://vuejs.org/images/logo.png"
  alt="Vue Logo"
>
1
2
3
4
<MyComponent
  foo="a"
  bar="b"
  baz="c"
/>
1
2
3
4
5

# Expresiones simples en plantillas altamente recomendado

Plantillas de componentes deben incluir expresiones simples, con expresiones más complejas refactorizadas en propiedades computadas o métodos.

Las expresiones complejas en sus plantillas los tornan menos declarativos. Debemos enfocarnos en escribir qué debe aparecer, no en cómo estamos computando dicho valor. También, las propiedades computadas y métodos permite que el código sea reutilizado.

Incorrecto

{{
  fullName.split(' ').map((word) => {
    return word[0].toUpperCase() + word.slice(1)
  }).join(' ')
}}
1
2
3
4
5

Correcto

<!-- En una plantilla -->
{{ normalizedFullName }}
1
2
// La expresión compleja ha sido movida a una propiedad computada
computed: {
  normalizedFullName() {
    return this.fullName.split(' ')
      .map(word => word[0].toUpperCase() + word.slice(1))
      .join(' ')
  }
}
1
2
3
4
5
6
7
8

# Propiedades computadas simples altamente recomendado

Propiedades computadas complejas deben ser separadadas en propiedades más simples, siempre que sea posible.

Explicación Detallada

Propiedades computadas simples y bien nombradas son:

  • Fácil de probar

    Cuando cada propiedad computada contiene solo una expresión simple, con pocas dependencias, es más fácil escribir tests confirmando que esta funciona correctamente.

  • Fácil de leer

    Simplificar las propiedades computadas le obliga a darle un nombre descriptivo a cada valor, incluso si no es reutilizado. Esto facilita a otros desarrolladores (y en el futuro, a usted) enfocarse en el código que les importa y descubrir lo que este hace.

  • Más adaptable al cambio en requirimientos

    Cualquier valor que pueda ser nombrado puede ser útil para la vista. Por ejemplo, podemos decidir mostrar un mensaje al usuario diciendo cuanto dinero ahorró. Podemos también decidir calcular los impuestos sobre las ventas, pero quizás mostrar estos valores separados y no como parte del precio final.

    Las propiedades computadas pequeñas y enfocadas hacen menos suposiciones sobre como se utilizará la información, por lo que requieren una menor refactorización a medida que cambian los requerimientos.

Incorrecto

computed: {
  price() {
    const basePrice = this.manufactureCost / (1 - this.profitMargin)
    return (
      basePrice -
      basePrice * (this.discountPercent || 0)
    )
  }
}
1
2
3
4
5
6
7
8
9

Correcto

computed: {
  basePrice() {
    return this.manufactureCost / (1 - this.profitMargin)
  },

  discount() {
    return this.basePrice * (this.discountPercent || 0)
  },

  finalPrice() {
    return this.basePrice - this.discount
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# Comillas en los valores de los atributos altamente recomendado

Los valores de atributos HTML no vacíos siempre deben estar dentro de comillas (simples o dobles, la que no sea utilizada en JS).

Si bien los valores de atributos sin espacios no requiren comillas en HTML, esta práctica usualmente conduce a evitar espacios, lo que causa que los valores de los atributos sean menos legibles.

Incorrecto

<input type=text>
1
<AppSidebar :style={width:sidebarWidth+'px'}>
1

Correcto

<input type="text">
1
<AppSidebar :style="{ width: sidebarWidth + 'px' }">
1

# Abreviación de directivas altamente recomendado

Las abreviación de directivas (: para v-bind:, @ para v-on: and # para v-slot) deben ser utilizadas siempre o nunca.

Incorrecto

<input
  v-bind:value="newTodoText"
  :placeholder="newTodoInstructions"
>
1
2
3
4
<input
  v-on:input="onInput"
  @focus="onFocus"
>
1
2
3
4
<template v-slot:header>
  <h1>Aquí podría ser un título de página</h1>
</template>

<template #footer>
  <p>Aquí son unas informaciones de contacto</p>
</template>
1
2
3
4
5
6
7

Correcto

<input
  :value="newTodoText"
  :placeholder="newTodoInstructions"
>
1
2
3
4
<input
  v-bind:value="newTodoText"
  v-bind:placeholder="newTodoInstructions"
>
1
2
3
4
<input
  @input="onInput"
  @focus="onFocus"
>
1
2
3
4
<input
  v-on:input="onInput"
  v-on:focus="onFocus"
>
1
2
3
4
<template v-slot:header>
  <h1>Aquí podría ser un título de página</h1>
</template>

<template v-slot:footer>
  <p>Aquí son unas informaciones de contacto</p>
</template>
1
2
3
4
5
6
7
<template #header>
  <h1>Aquí podría ser un título de página</h1>
</template>

<template #footer>
  <p>Aquí son unas informaciones de contacto</p>
</template>
1
2
3
4
5
6
7

# Reglas de prioridad C: Recomendadas (Minimizando Elecciones Arbitrarias y Sobrecarga Cognitiva)

# Orden de las opciones en un componente/instancia recomendado

Opciones de componentes/instancias deben ser ordenadas consistentemente.

Este es el orden por defecto que recomendamos para las opciones de los componentes. Estas están separadas en categorías, así usted sabe donde agregar nuevas propiedades de plugins.

  1. Consciencia Global (requiere conocimiento más allá del componente)

    • name
  2. Opciones del compilador de plantillas (cambia la manera de que son compiladas las plantillas)

    • compilerOptions
  3. Dependencias de plantilla (assets utilizados en la plantilla)

    • components
    • directives
  4. Composición (mezcla propiedades en las opciones)

    • extends
    • mixins
    • provide/inject
  5. Interfaz (la interfaz del componente)

    • inheritAttrs
    • props
    • emits
    • expose
  6. API de Composición (el punto de entrada para utilizar la API de composición)

    • setup
  7. Estado Local (propiedades reactivas locales)

    • data
    • computed
  8. Eventos (callbacks disparados por eventos reactivos)

    • watch
    • Eventos del ciclo de vida (en el orden que son invocados)
      • beforeCreate
      • created
      • beforeMount
      • mounted
      • beforeUpdate
      • updated
      • activated
      • deactivated
      • beforeUnmount
      • unmounted
      • errorCaptured
      • renderTracked
      • renderTriggered
  9. Propiedades no reactivas (propiedades de instancia independientes del sistema de reactividad)

    • methods
  10. Renderización (la descripción declarativa de la salida del componente)

    • template/render

# Orden de los atributos en un elemento recomendado

Los atributos de elementos (incluyendo componentes) deben ser ordenadas consistentemente.

Este es el orden por defecto que recomendamos para las opciones de los componentes. Estas están separadas en categorías, así usted sabe donde agregar nuevos atributos y directivas.

  1. Definición (provee las opciones del componente)

    • is
  2. Renderización de Listas (crea múltiples variaciones del mismo elemento)

    • v-for
  3. Condicionales (si el elemento es renderizado/mostrado o no)

    • v-if
    • v-else-if
    • v-else
    • v-show
    • v-cloak
  4. Modificadores de renderizado (cambia la forma en la que el elemento se renderiza)

    • v-pre
    • v-once
  5. Consciencia Global (requiere conocimiento más allá del componente)

    • id
  6. Atributos Únicos (atributos que requieren valores únicos)

    • ref
    • key
  7. Vinculación Bidireccional (combinación de vinculación y eventos)

    • v-model
  8. Otros Atributos (todos los atributos vinculados & desvinculados no especificados)

  9. Eventos (escuchadores de eventos de los componentes)

    • v-on
  10. Contenido (sobreescribe el contenido del elemento)

    • v-html
    • v-text

# Líneas vacías en las opciones de un componente/instancia recomendado

Usted puede añadir una línea vacía entre propiedades que se extienden en múltiples líneas, particularmente si las opciones no entrar en la pantalla sin scrollear.

Cuando un componente comienza a sentirse apretado o difícil de leer, añadir espacios entre propiedades que se extienden en múltiples líneas puede mejorar la legibilidad. En algunos editores, como Vim, opciones de formateo como esta pueden facilitar la navegación con el teclado.

Correcto

props: {
  value: {
    type: String,
    required: true
  },

  focused: {
    type: Boolean,
    default: false
  },

  label: String,
  icon: String
},

computed: {
  formattedValue() {
    // ...
  },

  inputClasses() {
    // ...
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// No tener espacios también es correcto, siempre y cuando
// el componente siga siendo fácil de leer y navegar.
props: {
  value: {
    type: String,
    required: true
  },
  focused: {
    type: Boolean,
    default: false
  },
  label: String,
  icon: String
},
computed: {
  formattedValue() {
    // ...
  },
  inputClasses() {
    // ...
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# Orden de los elementos de nivel superior de componentes de un solo archivo recomendado

Componentes de un solo archivo siempre deben ordenar las etiquetas <script>, <template>, y <style> consistentemente, con <style> por último, ya que al menos una de las otras dos siempre es necesaria.

Incorrecto

<style>/* ... */</style>
<script>/* ... */</script>
<template>...</template>
1
2
3
<!-- ComponentA.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
1
2
3
4
5
6
7
8
9

Correcto

<!-- ComponentA.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>
1
2
3
4
5
6
7
8
9
<!-- ComponentA.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
1
2
3
4
5
6
7
8
9

# Reglas de prioridad D: Utilizar con Precaución (Patrones Potencialmente Peligrosos)

# Selector de elemento con scoped utilizar con precaución

Los selectores de elementos deben ser evitados con scoped.

Prefiera selectores de clase sobre selectores de elementos en estilos scoped, ya que grandes números de selectores de elementos son lentos.

Explicación Detallada

Para aplicar alcance a los estilos, Vue añade un atributo único a los elementos del componente, como data-v-f3f3eg9. Luego, los selectores son modificados para que solo los elementos con ese atributo sean seleccionados (por ejemplo, button[data-v-f3f3eg9]).

El problema es que grandes números de selectores de atributo-elemento (por ejemplo, button[data-v-f3f3eg9]) será considerablemente más lento que selectores atributo-clase (por ejemplo, .btn-close[data-v-f3f3eg9]), así que los selectores de clase deben ser utilizados siempre que sea posible.

Incorrecto

<template>
  <button>×</button>
</template>

<style scoped>
button {
  background-color: red;
}
</style>
1
2
3
4
5
6
7
8
9

Correcto

<template>
  <button class="btn btn-close">×</button>
</template>

<style scoped>
.btn-close {
  background-color: red;
}
</style>
1
2
3
4
5
6
7
8
9

# Comunicación implícita entre componentes padre-hijo utilizar con precaución

Se debe preferir el uso de props y eventos para la comunicación entre componentes padre-hijo, en lugar de this.$parent o mutación de props.

Una aplicación Vue ideal es usada con props para abajo y eventos para arriba. Apegarse a esta convención hace que sus componentes sean más fáciles de entender. Sin embargo, hay casos border donde la mutación de props o el uso de this.$parent puede simplificar dos componentes que están fuertemente acopladas.

El problema es que también existen muchos casos simples donde estos patrones pueden ofrecer conveniencia. Cuidado: no se deje seducir por la conveniencia a corto plazo (escribir menos código) sobre la simpicidad (poder entender el flujo de su estado).

Incorrecto

app.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  template: '<input v-model="todo.text">'
})
1
2
3
4
5
6
7
8
9
10
app.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  methods: {
    removeTodo() {
      this.$parent.todos = this.$parent.todos.filter(todo => todo.id !== vm.todo.id)
    }
  },

  template: `
    <span>
      {{ todo.text }}
      <button @click="removeTodo">
        ×
      </button>
    </span>
  `
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Correcto

app.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  emits: ['input'],

  template: `
    <input
      :value="todo.text"
      @input="$emit('input', $event.target.value)"
    >
  `
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  emits: ['delete'],

  template: `
    <span>
      {{ todo.text }}
      <button @click="$emit('delete')">
        ×
      </button>
    </span>
  `
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Manejo de estado sin utilizar flux utilizar con precaución

Se debe preferir el uso de Vuex (opens new window) para el manejo del estado global, en vez de this.$root u un event bus global.

Manejar el estado en this.$root y/u utilizar un event bus global puede ser conveniente para casos simples, pero no son apropiados para la mayoría de las aplicaciones.

Vuex es la implementación oficial similar a flux para Vue, y ofrece no solo un lugar central para manejar estado, sino también herramientas para organizar, rastrear y depurar cambios de estado. Se integra bien en el ecosistema de Vue (incluyendo soporte completo de Vue DevTools).

Incorrecto

// main.js
import { createApp } from 'vue'
import mitt from 'mitt'
const app = createApp({
  data() {
    return {
      todos: [],
      emitter: mitt()
    }
  },

  created() {
    this.emitter.on('remove-todo', this.removeTodo)
  },

  methods: {
    removeTodo(todo) {
      const todoIdToRemove = todo.id
      this.todos = this.todos.filter(todo => todo.id !== todoIdToRemove)
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Correcto

// store/modules/todos.js
export default {
  state: {
    list: []
  },

  mutations: {
    REMOVE_TODO (state, todoId) {
      state.list = state.list.filter(todo => todo.id !== todoId)
    }
  },

  actions: {
    removeTodo ({ commit, state }, todo) {
      commit('REMOVE_TODO', todo.id)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- TodoItem.vue -->
<template>
  <span>
    {{ todo.text }}
    <button @click="removeTodo(todo)">
      X
    </button>
  </span>
</template>

<script>
import { mapActions } from 'vuex'

export default {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  methods: mapActions(['removeTodo'])
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24