英文:
What causes the slice is not a function error in this Vue 3 and TypeScript app?
问题
Here's the translated code part:
我一直在使用**Vue 3**、**TypeScript** 和 **The Movie Database (TMDB) API** 来开发单页面应用。
在 `src\components\MovieDetails.vue` 中有以下代码:
<template>
<div class="row">
<div class="col-sm-4 col-md-3">
<div class="poster-container text-center text-sm-start my-3">
<img v-if="movie"
:src="genericPoster"
:alt="movie?.title"
class="img-fluid shadow-sm"
/>
</div>
</div>
<div class="col-sm-8 col-md-9">
<h1 class="movie-title mt-4">{{ movie?.original_title }}</h1>
<p v-if="movie?.genres.length">
<strong class="pe-1">Genres:</strong>
<span
class="badge bg-secondary"
v-for="genre in movie?.genres"
:key="genre.id"
>{{ genre.name }}</span
>
</p>
<p v-if="movie?.vote_average" class="user-score">
<strong>User Score:</strong>
<span class="score" :class="movieQuality">{{ Number(movie?.vote_average).toFixed(2) }}</span>
</p>
<div v-if="movie?.overview">
<h2 class="section-title">Overview</h2>
<p>{{ movie.overview }}</p>
</div>
<div v-if="movieTrailers.length" class="mb-3">
<h2 class="section-title">Trailers</h2>
<TrailerCarousel :movieTrailers="movieTrailers" />
</div>
<div v-if="movieCast.length" class="cast-container">
<h2 class="section-title">Cast</h2>
<div class="row">
<div
v-for="actor in movieCast.slice(0, 12)"
:key="actor['id']"
class="col-sm-3"
>
<ActorCard :actor="actor" />
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { useRoute } from "vue-router";
import env from "../env";
import { Movie } from "@/models/Movie";
import { Trailer } from "@/models/Trailer";
import { MovieCast } from "@/models/MovieCast";
import TrailerCarousel from "./TrailerCarousel.vue";
import ActorCard from "./ActorCard.vue";
export default defineComponent({
name: "MovieDetails",
components: {
TrailerCarousel,
ActorCard,
},
data: () => ({
route: useRoute(),
genericPosterBig: require('../assets/generic-poster.png'),
movie: null as Movie | null,
movieQuality: String as unknown | 'bad',
movieCast: Array as unknown | MovieCast[],
movieTrailers: Array as unknown | Trailer[],
}),
mounted() {
this.getMovieDetails();
this.getMovieTrailers();
this.getMovieCast();
},
methods: {
getMovieDetails() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}?api_key=${env.api_key}`
)
.then((response) => {
this.movie = response.data;
// 获取电影后,设置其质量
this.setMovieQuality();
})
.catch((err) => console.log(err));
},
setMovieQuality() {
if (Number(this.movie?.vote_average) >= 7) {
this.movieQuality = 'good';
} else if(Number(this.movie?.vote_average) < 7 && Number(this.movie?.vote_average) > 5.5) {
this.movieQuality = 'average';
} else {
this.movieQuality = 'bad';
}
},
getMovieTrailers() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}/videos?api_key=${env.api_key}`
)
.then((response) => {
this.movieTrailers = response.data.results;
})
.catch((err) => console.log(err));
},
getMovieCast() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}/credits?api_key=${env.api_key}`
)
.then((response) => {
this.movieCast = response.data.cast;
})
.catch((err) => console.log(err));
},
},
computed: {
genericPoster() {
return !this.movie?.poster_path
? this.genericPosterBig
: `https://image.tmdb.org/t/p/w500/${this.movie?.poster_path}`
},
},
watch: {
"$route.params.id"() {
this.getMovieDetails();
this.getMovieTrailers();
this.getMovieCast();
},
},
});
</script>
在 `src\models\MovieCast.ts` 中:
export interface MovieCast {
adult?: boolean;
character?: string;
name?: string;
profile_path?: string;
}
而不是这两行代码:
movieCast: Array as unknown | MovieCast[]
movieTrailers: Array as unknown | Trailer[]
我*曾经*这样写过:
movieTrailers: [],
movieCast: [],
我做出了这个改变,以便我有一个更加**严格/强类型化**的应用程序。
### 问题
自从做出更改以来,控制台显示错误:
> TypeError: _ctx.movieCast.slice is not a function
<div
v-for="actor in movieCast.slice(0, 12)"
:key="actor['id']"
class="col-sm-3"
>
<ActorCard :actor="actor" />
</div>
有一个**[Stackblitz](https://stackblitz.com/edit/vue3-typescript-vue-cli-starter-7y9c7v)**,其中包含工作中的应用程序。
### 问题
1. 我做错了什么?
2. 最可靠的解决方法是什么?
Please let me know if you need further assistance or have any questions.
英文:
I have been working on an SPA with Vue 3, TypeScript and The Movie Database (TMDB) API.
In src\components\MovieDetails.vue
I have:
<template>
<div class="row">
<div class="col-sm-4 col-md-3">
<div class="poster-container text-center text-sm-start my-3">
<img v-if="movie"
:src="genericPoster"
:alt="movie?.title"
class="img-fluid shadow-sm"
/>
</div>
</div>
<div class="col-sm-8 col-md-9">
<h1 class="movie-title mt-4">{{ movie?.original_title }}</h1>
<p v-if="movie?.genres.length">
<strong class="pe-1">Genres:</strong>
<span
class="badge bg-secondary"
v-for="genre in movie?.genres"
:key="genre.id"
>{{ genre.name }}</span
>
</p>
<p v-if="movie?.vote_average" class="user-score">
<strong>User Score:</strong>
<span class="score" :class="movieQuality">{{
Number(movie?.vote_average).toFixed(2)
}}</span>
</p>
<div v-if="movie?.overview">
<h2 class="section-title">Overview</h2>
<p>{{ movie.overview }}</p>
</div>
<div v-if="movieTrailers.length" class="mb-3">
<h2 class="section-title">Trailers</h2>
<TrailerCarousel :movieTrailers="movieTrailers" />
</div>
<div v-if="movieCast.length" class="cast-container">
<h2 class="section-title">Cast</h2>
<div class="row">
<div
v-for="actor in movieCast.slice(0, 12)"
:key="actor['id']"
class="col-sm-3"
>
<ActorCard :actor="actor" />
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { useRoute } from "vue-router";
import env from "../env";
import { Movie } from "@/models/Movie";
import { Trailer } from "@/models/Trailer";
import { MovieCast } from "@/models/MovieCast";
import TrailerCarousel from "./TrailerCarousel.vue";
import ActorCard from "./ActorCard.vue";
export default defineComponent({
name: "MovieDetails",
components: {
TrailerCarousel,
ActorCard,
},
data: () => ({
route: useRoute(),
genericPosterBig: require('../assets/generic-poster.png'),
movie: null as Movie | null,
movieQuality: String as unknown | 'bad',
movieCast: Array as unknown | MovieCast[]
movieTrailers: Array as unknown | Trailer[]
}),
mounted() {
this.getMovieDetails();
this.getMovieTrailers();
this.getMovieCast();
},
methods: {
getMovieDetails() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}?api_key=${env.api_key}`
)
.then((response) => {
this.movie = response.data;
// Once you get the movie, set its quality
this.setMovieQuality();
})
.catch((err) => console.log(err));
},
setMovieQuality() {
if (Number(this.movie?.vote_average) >= 7) {
this.movieQuality = 'good';
} else if(Number(this.movie?.vote_average) < 7 && Number(this.movie?.vote_average) > 5.5) {
this.movieQuality = 'average';
} else {
this.movieQuality = 'bad';
}
},
getMovieTrailers() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}/videos?api_key=${env.api_key}`
)
.then((response) => {
this.movieTrailers = response.data.results;
})
.catch((err) => console.log(err));
},
getMovieCast() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}/credits?api_key=${env.api_key}`
)
.then((response) => {
this.movieCast = response.data.cast;
})
.catch((err) => console.log(err));
},
},
computed: {
genericPoster() {
return !this.movie?.poster_path
? this.genericPosterBig
: `https://image.tmdb.org/t/p/w500/${this.movie?.poster_path}`
},
},
watch: {
"$route.params.id"() {
this.getMovieDetails();
this.getMovieTrailers();
this.getMovieCast();
},
},
});
</script>
In src\models\MovieCast.ts
:
export interface MovieCast {
adult?: boolean;
character?: string;
name?: string;
profile_path?: string;
}
In stead of these 2 lines in the components
movieCast: Array as unknown | MovieCast[]
movieTrailers: Array as unknown | Trailer[]
I used to have:
movieTrailers: [],
movieCast: [],
I have made the change so that I would have a more strictly/strongly typed app.
The problem
Since the change, the console shows the error:
> TypeError: _ctx.movieCast.slice is not a function
<div
v-for="actor in movieCast.slice(0, 12)"
:key="actor['id']"
class="col-sm-3"
>
<ActorCard :actor="actor" />
</div>
There is a Stackblitz too, with the working app.
Questions
- What am I doing wrong?
- What is the most reliable way to fix this issue?
答案1
得分: 1
If you are assigning a non-array, you will also get an error. Try logging the type, and see what is actually returned.
console.log('movieCast', response.data.cast)
this.movieCast = response.data.cast;
Use a conditional operator
to prevent an error while your async value is undefined
and calculating. You could also wrap the v-for
in a v-if
and check for undefined.
v-for="actor in movieCast?.slice(0, 12)"
英文:
If you are assigning a non-array, you will also get an error. Try logging the type, and see what is actually returned.
console.log('movieCast', response.data.cast)
this.movieCast = response.data.cast;
Use a conditional operator
to prevent an error while your async value is undefined
and calculating. You could also wrap the v-for
in a v-if
and check for undefined.
v-for="actor in movieCast?.slice(0, 12)"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论