admin管理员组

文章数量:1406156

I have question about Vue.js. How can i fix this? I didn't find anything in documentation. I've got this error: "[vue/require-v-for-key] Elements in iteration expect to have 'v-bind:key' directives."

And this: "Elements in iteration expect to have 'v-bind:key' directives."

I have this i my Roulette.vue

<template>
  <div class="roulette">
    <h1>Roulette</h1>
    <div class="radio" v-for="genre in genres"> **here**
      <input 
        @change="onGenrePick"
        type="radio"
        name="genre"
        v-bind:id="genre.id"
        v-bind:value="genre.id">
      <label v-bind:for="genre.id">{{genre.name}}</label>
    </div>
    <Button class="btn" :onClick="roll">Roll</Button>

    <MovieCard 
      v-if="!!movie"
      v-bind:image="serviceGetImagePath(movie.poster_path)"
      v-bind:title="movie.title"
      v-bind:releaseDate="serviceFormatYear(movie.release_date)"
      v-bind:id="movie.id"
      v-bind:voteAverage="movie.vote_average"/>
  </div>
</template>

<script>
  import MovieCard from '../ponents/MovieCard'
  import Button from '../ponents/Button'
  import {movieService} from '../mixins/movieService'

  export default {

    name: 'Roulette',
    ponents: {Button, MovieCard},
    mixins: [movieService],
    mounted: async function () {
      this.genres = await this.serviceGetGenres()
    },
    data: () => ({
      genres: [],
      pickedGenres: new Set(),
      movie: null
    }),
    methods: {
      async roll() {
        const genreIds = Array.from(this.pickedGenres)
        const movies = await this.serviceGetMoviesByGenre(genreIds)
        this.movie = movies[this.getRandom(movies.length)]
      },
      onGenrePick(e) {
        this.pickedGenres.add(e.target.value)
      },
      getRandom(max) {
        return Math.floor(Math.random() * max - 1)
      }
    }
  }
</script>

<style scoped lang="scss">
  .roulette {
    margin: 40px;
  }

  .btn {
    display: block;
    min-width: 220px;
  }

  .radio {
    display: inline-block;
    margin: 20px 10px;

    > label {
      margin-left: 5px;
    }
  }
</style>

And in my UpingMovies.vue also

<template>
  <div class="wrapper" v-if="movies.length">
    <MovieCard 
      v-for="movie in movies" **here**
      v-bind:image="serviceGetImagePath(movie.poster_path)"**here**
      v-bind:title="movie.title"**here**
      v-bind:releaseDate="serviceFormatYear(movie.release_date)"**here**
      v-bind:id="movie.id"**here**
      v-bind:voteAverage="movie.vote_average"/>**here**
    <div class="loader">
      <Button class="loader__btn" :onClick="loadNextPage">Load</Button>
    </div>
    <router-link :to="routes.roulette.path">
      <div class="roulette">
        <img src="../assets/roulette.png" alt="Roulette">
      </div>
    </router-link>
  </div>
  <Loader v-else/>
</template>

<script>
  import Button from '../ponents/Button'
  import MovieCard from '../ponents/MovieCard'
  import Loader from '../ponents/Loader'
  import { movieService } from '../mixins/movieService'
  import routes from '../router/routes'

  export default {

    name: 'UpingMovies',
    mixins: [movieService],
    ponents: { Button, MovieCard, Loader },
    data: () => ({
      movies: [],
      page: 1,
      routes
    }),
    mounted() {
      this.getMovies(this.page)
    },
    methods: {
      getMovies: async function (page) {
        const movies = await this.serviceGetMovies(page)
        this.movies.push(...movies)
      },
      loadNextPage() {
        this.getMovies(++this.page)
      }
    }
  }
</script>

<style scoped lang="scss">
  .wrapper {
    width: 100%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    margin-top: 40px;
    margin-bottom: 40px;
  }
  .loader {
    width: 100%;
    text-align: center;
    margin-top: 40px;
    margin-bottom: 40px;
    &__btn {
      border: 5px dashed white;
      background-color: transparent;
      border-radius: 50%;
      width: 80px;
      height: 80px;
      font-weight: bold;
      text-transform: uppercase;
      transition: border-radius 100ms ease-in-out, width 120ms ease-in-out 120ms;
      &:hover {
        border-radius: 0;
        background-color: rgba(white, 0.1);
        width: 200px;
      }
    }
  }
  .roulette {
    cursor: pointer;
    position: fixed;
    right: 25px;
    bottom: 25px;
    > img {
      opacity: .8;
      animation: rotate 5s infinite;
      width: 70px;
      height: auto;
      transition: opacity 220ms linear;
      &:hover {
        opacity: 1;
      }
    }
  }
  @keyframes rotate {
    0% {
      transform: rotate(0);
    }
    100% {
      transform: rotate(360deg);
    }
  }
</style>

I have question about Vue.js. How can i fix this? I didn't find anything in documentation. I've got this error: "[vue/require-v-for-key] Elements in iteration expect to have 'v-bind:key' directives."

And this: "Elements in iteration expect to have 'v-bind:key' directives."

I have this i my Roulette.vue

<template>
  <div class="roulette">
    <h1>Roulette</h1>
    <div class="radio" v-for="genre in genres"> **here**
      <input 
        @change="onGenrePick"
        type="radio"
        name="genre"
        v-bind:id="genre.id"
        v-bind:value="genre.id">
      <label v-bind:for="genre.id">{{genre.name}}</label>
    </div>
    <Button class="btn" :onClick="roll">Roll</Button>

    <MovieCard 
      v-if="!!movie"
      v-bind:image="serviceGetImagePath(movie.poster_path)"
      v-bind:title="movie.title"
      v-bind:releaseDate="serviceFormatYear(movie.release_date)"
      v-bind:id="movie.id"
      v-bind:voteAverage="movie.vote_average"/>
  </div>
</template>

<script>
  import MovieCard from '../ponents/MovieCard'
  import Button from '../ponents/Button'
  import {movieService} from '../mixins/movieService'

  export default {

    name: 'Roulette',
    ponents: {Button, MovieCard},
    mixins: [movieService],
    mounted: async function () {
      this.genres = await this.serviceGetGenres()
    },
    data: () => ({
      genres: [],
      pickedGenres: new Set(),
      movie: null
    }),
    methods: {
      async roll() {
        const genreIds = Array.from(this.pickedGenres)
        const movies = await this.serviceGetMoviesByGenre(genreIds)
        this.movie = movies[this.getRandom(movies.length)]
      },
      onGenrePick(e) {
        this.pickedGenres.add(e.target.value)
      },
      getRandom(max) {
        return Math.floor(Math.random() * max - 1)
      }
    }
  }
</script>

<style scoped lang="scss">
  .roulette {
    margin: 40px;
  }

  .btn {
    display: block;
    min-width: 220px;
  }

  .radio {
    display: inline-block;
    margin: 20px 10px;

    > label {
      margin-left: 5px;
    }
  }
</style>

And in my UpingMovies.vue also

<template>
  <div class="wrapper" v-if="movies.length">
    <MovieCard 
      v-for="movie in movies" **here**
      v-bind:image="serviceGetImagePath(movie.poster_path)"**here**
      v-bind:title="movie.title"**here**
      v-bind:releaseDate="serviceFormatYear(movie.release_date)"**here**
      v-bind:id="movie.id"**here**
      v-bind:voteAverage="movie.vote_average"/>**here**
    <div class="loader">
      <Button class="loader__btn" :onClick="loadNextPage">Load</Button>
    </div>
    <router-link :to="routes.roulette.path">
      <div class="roulette">
        <img src="../assets/roulette.png" alt="Roulette">
      </div>
    </router-link>
  </div>
  <Loader v-else/>
</template>

<script>
  import Button from '../ponents/Button'
  import MovieCard from '../ponents/MovieCard'
  import Loader from '../ponents/Loader'
  import { movieService } from '../mixins/movieService'
  import routes from '../router/routes'

  export default {

    name: 'UpingMovies',
    mixins: [movieService],
    ponents: { Button, MovieCard, Loader },
    data: () => ({
      movies: [],
      page: 1,
      routes
    }),
    mounted() {
      this.getMovies(this.page)
    },
    methods: {
      getMovies: async function (page) {
        const movies = await this.serviceGetMovies(page)
        this.movies.push(...movies)
      },
      loadNextPage() {
        this.getMovies(++this.page)
      }
    }
  }
</script>

<style scoped lang="scss">
  .wrapper {
    width: 100%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    margin-top: 40px;
    margin-bottom: 40px;
  }
  .loader {
    width: 100%;
    text-align: center;
    margin-top: 40px;
    margin-bottom: 40px;
    &__btn {
      border: 5px dashed white;
      background-color: transparent;
      border-radius: 50%;
      width: 80px;
      height: 80px;
      font-weight: bold;
      text-transform: uppercase;
      transition: border-radius 100ms ease-in-out, width 120ms ease-in-out 120ms;
      &:hover {
        border-radius: 0;
        background-color: rgba(white, 0.1);
        width: 200px;
      }
    }
  }
  .roulette {
    cursor: pointer;
    position: fixed;
    right: 25px;
    bottom: 25px;
    > img {
      opacity: .8;
      animation: rotate 5s infinite;
      width: 70px;
      height: auto;
      transition: opacity 220ms linear;
      &:hover {
        opacity: 1;
      }
    }
  }
  @keyframes rotate {
    0% {
      transform: rotate(0);
    }
    100% {
      transform: rotate(360deg);
    }
  }
</style>
Share Improve this question edited Jan 21, 2020 at 14:20 Vectrobyte 1,48515 silver badges33 bronze badges asked Jan 21, 2020 at 14:14 Ivan RadunkovićIvan Radunković 1051 gold badge3 silver badges16 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 6

Vue internally uses unique keys for each loop to determine which element to update at which point during an update process. Therefore every v-for needs a v-bind:key attribute to work properly. In your special case this would be as the following:

<div class="radio" v-for="genre in genres" v-bind:key="someUniqueId"> **here**

You can use the current loop index as ID or anything else.

本文标签: javascriptCustom elements in iteration require 39vbindkey39 directives in VuejsStack Overflow