Representación de listas y directiva v-for de Vue | Programar Plus

La representación de listas es una de las prácticas más utilizadas en el desarrollo web front-end. La representación dinámica de listas se usa a menudo para presentar una serie de información agrupada de manera similar en un formato conciso y fácil de usar para el usuario. En casi todas las aplicaciones web que usamos, podemos ver listas de contenido en numerosas áreas de la aplicación.

En este artículo reuniremos una comprensión de Vue v-for Directiva en la generación de listas dinámicas, así como pasar por algunos ejemplos de por qué el key El atributo debe usarse al hacerlo.

Dado que explicaremos las cosas detalladamente a medida que comencemos a escribir el código, este artículo asume que tendrá muy poco o ningún conocimiento con Vue (y/u otros marcos de JavaScript).

Estudio de caso: Twitter

vamos a usar Gorjeo como caso de estudio para este artículo.

Cuando iniciamos sesión y en la ruta de índice principal de Twitter, se nos presenta una vista similar a esta:

Una captura de pantalla de la página de inicio de Twitter que muestra una lista de tweets de la línea de tiempo del autor.

En la página de inicio, nos hemos acostumbrado a ver una lista de tendencias, una lista de tweets, una lista de seguidores potenciales, etc. El contenido que se muestra en estas listas depende de una multitud de factores: nuestro historial de Twitter, a quién seguimos, nuestros gustos, etc. Como resultado, podemos decir que todos estos datos son dinámicos.

Aunque estos datos se obtienen dinámicamente, la forma en que se muestran sigue siendo la misma. Esto se debe en parte al uso componentes web reutilizables.

Por ejemplo; podemos ver la lista de tweets como una lista de solo tweet-component elementos. podemos pensar en tweet-component como un caparazón que toma datos de todo tipo, como el nombre de usuario, el identificador, el tweet y el avatar, entre otras piezas, y que simplemente muestra esas piezas en un marcado coherente.

Un diagrama que disecciona los elementos de un tweet, incluido el nombre de usuario, el identificador, el avatar, el cuerpo del tweet y el recuento de Me gusta.

Digamos que queremos representar una lista de componentes (por ejemplo, una lista de tweet-component artículos) basados ​​en una gran fuente de datos obtenida de un servidor. En Vue, lo primero que debe venir a la mente para lograr esto es el v-for directiva.

La directiva v-for

El v-for La directiva se utiliza para representar una lista de elementos basada en una fuente de datos. La directiva se puede utilizar en un elemento de plantilla y requiere una sintaxis específica del tipo:

Una imagen que muestra una directiva Vue for de v-for es igual a elemento en elementos, donde elemento es el alias y elementos es la recopilación de datos.

Veamos un ejemplo de esto en la práctica. Primero, supondremos que ya hemos obtenido una colección de datos de tweets:

const tweets = [
  {
    id: 1,
    name: 'James',
    handle: '@jokerjames',
    img: 'https://semantic-ui.com/images/avatar2/large/matthew.png',
    tweet: "If you don't succeed, dust yourself off and try again.",
    likes: 10,
  },
  { 
    id: 2,
    name: 'Fatima',
    handle: '@fantasticfatima',
    img: 'https://semantic-ui.com/images/avatar2/large/molly.png',
    tweet: 'Better late than never but never late is better.',
    likes: 12,
  },
  {
    id: 3,
    name: 'Xin',
    handle: '@xeroxin',
    img: 'https://semantic-ui.com/images/avatar2/large/elyse.png',
    tweet: 'Beauty in the struggle, ugliness in the success.',
    likes: 18,
  }
]

tweets es una colección de tweet objetos con cada tweet que contiene detalles de ese tweet en particular: un identificador único, el nombre/identificador de la cuenta, el mensaje del tweet, etc. Ahora intentemos usar el v-for Directiva para generar una lista de componentes de tweet basados ​​en estos datos.

En primer lugar, crearemos la instancia de Vue, el corazón de la aplicación Vue. Montaremos/adjuntaremos nuestra instancia a un elemento DOM de id app y asignar el tweets colección como parte del objeto de datos de la instancia.

new Vue({
  el: '#app',
  data: {
    tweets
  }
});

Ahora seguiremos adelante y crearemos un tweet-component esa hora v-for directiva utilizará para representar una lista. Usaremos el global Vue.component constructor para crear un componente llamado tweet-component:

Vue.component('tweet-component', {
  template: `  
    <div class="tweet">
      <div class="box">
        <article class="media">
          <div class="media-left">
            <figure class="image is-64x64">
              <img :src="https://css-tricks.com/list-rendering-and-vues-v-for-directive/tweet.img" alt="Image">
            </figure>
          </div>
          <div class="media-content">
            <div class="content">
              <p>
                <strong>{{tweet.name}}</strong> <small>{{tweet.handle}}</small>
                <br>
                {{tweet.tweet}}
              </p>
            </div>
              <div class="level-left">
                <a class="level-item">
                  <span class="icon is-small"><i class="fas fa-heart"></i></span>
                  <span class="likes">{{tweet.likes}}</span>
                </a>
              </div>
          </div>
        </article>
      </div>
    </div>  
  `,
  props: {
    tweet: Object
  }
});

Algunas cosas interesantes a tener en cuenta aquí.

  1. El tweet-component espera un tweet accesorio de objeto como se ve en el requisito de validación de accesorios (props: {tweet: Object}). Si el componente se renderiza con un tweet prop que no es un objeto, Vue emitirá advertencias.
  2. Vinculamos las propiedades del accesorio de objeto de tweet a la plantilla del componente con la ayuda de la sintaxis de Mustache: {{ }}.
  3. El marcado del componente adapta el elemento Caja de Bulma, ya que representa un buen parecido con un tweet.

En la plantilla HTML, necesitaremos crear el marcado donde se montará nuestra aplicación Vue (es decir, el elemento con la identificación de app). Dentro de este marcado, usaremos el v-for Directiva para generar una lista de tweets. Ya que tweets es la recopilación de datos sobre la que estaremos iterando, tweet será un alias apropiado para usar en la directiva. En cada renderizado tweet-component, también pasaremos el iterado tweet objeto como accesorios para acceder a él en el componente.

<div id="app" class="columns">
  <div class="column">
    <tweet-component v-for="tweet in tweets" :tweet="tweet"/>
  </div>
</div>

Independientemente de cuántos objetos de tweet más se introduzcan en la colección; o cómo cambiarán con el tiempo: nuestra configuración siempre mostrará todos los tweets de la colección con el mismo marcado que esperamos.

Con la ayuda de un CSS personalizado, nuestra aplicación se verá así:

Vea el Twitter Pen Simple Feed #1 por Hassan Dj (@itslit) en CodePen.

Aunque todo funciona como se esperaba, es posible que se nos solicite un consejo de Vue en la consola de nuestro navegador:

[Vue tip]: <tweet-component v-for="tweet in tweets">: component lists rendered with v-for should have explicit keys...

Es posible que no pueda ver la advertencia en la consola del navegador cuando ejecute el código a través de CodePen.

¿Por qué Vue nos dice que especifiquemos claves explícitas en nuestra lista cuando todo funciona como se esperaba?

llave

Es una práctica común especificar un atributo clave para cada elemento iterado dentro de un renderizado. v-for lista. Esto se debe a que Vue usa el key atributo para crear enlaces únicos para la identidad de cada nodo.

Expliquemos esto un poco más: si hubo cambios en la interfaz de usuario dinámica en nuestra lista (por ejemplo, el orden de los elementos de la lista se baraja), Vue optará por cambiar los datos dentro de cada elemento en lugar de mover los elementos DOM en consecuencia. Esto no será un problema en la mayoría de los casos. Sin embargo, en ciertos casos en los que nuestro v-for list depende del estado del DOM y/o del estado del componente secundario, esto puede causar un comportamiento no deseado.

Veamos un ejemplo de esto. ¿Qué pasaría si nuestro componente de tweet simple ahora contuviera un campo de entrada que permitiría al usuario responder directamente al mensaje de tweet? Ignoraremos cómo se podría enviar esta respuesta y simplemente abordaremos el nuevo campo de entrada:

Una maqueta del tweet que estamos tratando de crear que se ve exactamente como el diagrama anterior.  Este tiene un componente adicional que incluye una entrada de texto para enviar una respuesta.

Incluiremos este nuevo campo de entrada en la plantilla de tweet-component:

Vue.component('tweet-component', {
  template: `
    <div class="tweet">
      <div class="box">
        // ...
      </div>
      <div class="control has-icons-left has-icons-right">
        <input class="input is-small" placeholder="Tweet your reply..." />
        <span class="icon is-small is-left">
          <i class="fas fa-envelope"></i>
        </span>
      </div>
    </div>
  `,
  props: {
    tweet: Object
  }
});

Supongamos que queremos introducir otra función nueva en nuestra aplicación. Esta característica implicaría permitir al usuario mezclar aleatoriamente una lista de tweets.

Para hacer esto; primero podemos incluir un “Shuffle!” botón en nuestra plantilla HTML:

<div id="app" class="columns">
  <div class="column">
    <button class="is-primary button" @click="shuffle">Shuffle!</button>
    <tweet-component  v-for="tweet in tweets" :tweet="tweet"/>
  </div>
</div>

Hemos adjuntado un detector de eventos de clic en el elemento de botón para llamar a un shuffle método cuando se activa. En nuestra instancia de Vue; crearemos el shuffle método responsable de barajar aleatoriamente los tweets colección en la instancia. Usaremos el método _shuffle de lodash para lograr esto:

new Vue({
  el: '#app',
  data: {
    tweets
  },
  methods: {
    shuffle() {
      this.tweets = _.shuffle(this.tweets)
    }
  }
});

¡Vamos a probarlo! Si hacemos clic en barajar un par de veces; Notaremos que los elementos de nuestro tweet se ordenan aleatoriamente con cada clic.

Vea el Pen Simple Twitter Feed #2 por Hassan Dj (@itslit) en CodePen.

Sin embargo, si escribimos alguna información en la entrada de cada componente, haga clic en barajar; notaremos que sucede algo peculiar:

Una captura de pantalla animada de un botón Shuffle al que se hace clic.  El orden de los tweets se mezcla, pero los campos de texto para enviar respuestas no.

Dado que no hemos optado por utilizar el key atributo, Vue no ha creado enlaces únicos para cada nodo de tweet. Como resultado, cuando nuestro objetivo es reordenar los tweets, Vue adopta el enfoque de ahorro de mayor rendimiento para simplemente cambiar (o parchear) los datos en cada elemento. Dado que el estado DOM temporal (es decir, el texto ingresado) permanece en su lugar, experimentamos este desajuste no deseado.

Aquí hay un diagrama que nos muestra los datos que se parchean en cada elemento y el estado DOM que permanece en su lugar:

Un diagrama de un tweet que describe los elementos parcheados que se incluyen en la reproducción aleatoria y el campo de texto que es un elemento DOM y permanece en su lugar.

Para evitar esto; tendremos que asignar un único llave a cada tweet-component representado en la lista. Usaremos el id de un tweet ser el identificador único ya que deberíamos decir con seguridad un tweet id no debe ser igual a la de otro. Debido a que estamos usando valores dinámicos, usaremos el v-bind directiva para vincular nuestra clave a la tweet.id:

<div id="app" class="columns">
  <div class="column">
    <button class="is-primary button" @click="shuffle">Shuffle!</button>
    <tweet-component  v-for="tweet in tweets" :tweet="tweet" :key="tweet.id" />
  </div>
</div>

Ahora, Vue reconoce la identidad del nodo de cada tweet; y así reordenará los componentes cuando tengamos la intención de barajar la lista.

Una captura de pantalla animada de los tweets que se mezclan correctamente cuando se hace clic en el botón Shuffle.  Ahora, todos los elementos del tweet se incluyen en la reproducción aleatoria, incluido el campo de texto.

Dado que cada componente de tweet ahora se mueve en consecuencia, podemos llevar esto un paso más allá y usar Vue transition-group para mostrar cómo se están reordenando los elementos.

Para ello, añadiremos el transition-group elemento como un envoltorio para el v-for lista. Especificaremos un nombre de transición de tweets y declarar que el grupo de transición debe ser representado como un div elemento.

<div id="app" class="columns">
  <div class="column">
    <button class="is-primary button" @click="shuffle">Shuffle!</button>
    <transition-group name="tweets" tag="div">
      <tweet-component  v-for="tweet in tweets" :tweet="tweet" :key="tweet.id" />
    </transition-group>
  </div>
</div>

Según el nombre de la transición, Vue reconocerá automáticamente si se han especificado transiciones/animaciones CSS. Dado que nuestro objetivo es invocar una transición para el movimiento de elementos en la lista; Vue buscará una transición CSS específica a lo largo de las líneas de tweets-move (donde tweets es el nombre dado a nuestro grupo de transición). Como resultado, introduciremos manualmente un .tweets-move clase que tiene un tipo y tiempo de transición especificados:

#app .tweets-move {
  transition: transform 1s;
}

Esta es una mirada muy breve a la aplicación de transiciones de lista. ¡Asegúrese de consultar los documentos de Vue para obtener información detallada sobre todos los diferentes tipos de transiciones que se pueden aplicar!

Nuestra tweet-component los elementos ahora harán una transición adecuada entre ubicaciones cuando se invoque una reproducción aleatoria. ¡Darle una oportunidad! Escriba alguna información en los campos de entrada y haga clic en “¡Mezclar!” unas pocas veces.

Vea el Pen Simple Twitter Feed #3 por Hassan Dj (@itslit) en CodePen.

Bastante genial, ¿verdad? Sin el key atributo, el elemento del grupo de transición no se puede usar para crear transiciones de lista ya que los elementos se parchean en su lugar en lugar de reordenarse.

Si el key atributo siempre se utiliza? Se recomienda. Los documentos de Vue especifican que el atributo clave solo debe omitirse si:

  • Intencionalmente, queremos la forma predeterminada de aplicar parches a los elementos por motivos de rendimiento.
  • El contenido del DOM es bastante simple.

Conclusión

¡Y ahí lo tenemos! Esperemos que este breve artículo describa cuán útil es el v-for directiva también proporciona un poco más de contexto de por qué la key El atributo se usa a menudo. ¡Avíseme si tiene alguna pregunta/idea de cualquier tipo!

Si le gustó mi estilo de escritura y está potencialmente interesado en aprender a crear aplicaciones con Vue.js, es posible que le guste el libro. Fullstack Vue: la guía completa de Vue.js que ayudé a publicar! El libro cubre numerosas facetas de Vue, incluidas, entre otras, el enrutamiento, la administración de estado simple, el manejo de formularios, Vuex, la persistencia del servidor y las pruebas. Si estás interesado, puedes obtener más información en nuestra web, https://fullstack.io/vue.