详情页开发
接下来开发详情页(detail 页面),页面 UI 效果图如图12-6所示。

Figure 1. 图12-6 详情页效果图
在 views 目录下新建 detail 文件目录,由于详情页逻辑复杂一些,我们将详情页拆分成 movieinfo.vue、movieactors.vue、moviecomments.vue 三个组件,其目录结构如图12-7所示。

Figure 2. 图12-7 详情页目录结构
电影基本信息组件
在 detail 目录下新建 detail.vue,用来作为父组件,其核心代码如下:
<div class="detail-container">
<div class="left-content">
<movieinfo />// 基本信息
<movieactors />// 演员信息
<moviecomments />// 评论信息
</div>
</div>
该组件主要为父组件的壳子,用于设置基本的样式,没有其他逻辑。
在 detail 目录下新建 movieinfo.vue,用来作为电影信息组件,其核心代码如下:
setup(){
const store = Vuex.useStore()
let detailData = ref({})
let actors = reactive({
orgin:[],
short:[],
isShowMore: true
})
let rate = reactive({
list:[],
betterList:[]
})
const route = useRoute()
let id = computed(() => route.query.id);
onMounted(async () => {
// 获取数据
detailData.value = await service.get(configapi.detail(id.value),{})
// 设置当前电影的title,为了通知其他组件,所以放在Vuex的Store中
store.commit('setTitle',detailData.value.title)
actors.orgin = detailData.value.actors||[]
actors.short = actors.orgin.slice(0,3)
actors.isShowMore = actors.orgin.length > 3
// 渲染评分高低排名
let rateData = await service.get(configapi.rate(id.value),{})
rate.list = dealRateData(rateData)
rate.betterList = rateData.type_ranks||[]
});
// 格式化评分数据
const dealRateData = (rateData)=>{
// 100%的最大宽度
let maxwidth = 70
let list = []
for (let i = 0 ; i < rateData.stats.length ; i++) {
let r = rateData.stats[i].toFixed(3)*100
// 以此通过评分计算百分比宽度
list.push({
index: i+1,
count:r,
width: r*maxwidth/100
})
}
return list.reverse()// 从高到低排列
}
// 展开所有演员名字
const expand = ()=>{
actors.short = actors.orgin
actors.isShowMore = false
}
return {
detailData,
actors,
expand,
rate
}
},
其主要业务逻辑如下:
-
获取基本信息数据,对将数据分别进行处理,供基本内容展示和评分排名使用。
-
在获取到标题后,利用 Vuex 通知其他需要标题的组件。
-
在基本信息中,如果演员数据太长,则默认只取前三个名字,当单击展开时,再将所有名字平铺出来。
-
在评分排名渲染时,设置一个最大宽度,根据每种区间得分的占比分别设置不同的宽度。
电影演员信息组件
在 detail 目录下新建 movieactors.vue,用来作为电影演员图片列表组件,其核心代码如下:
setup(){
const store = Vuex.useStore()
// 从Vuex的Store中获取title
const title = computed(() => store.state.detailTitle);
let detailData = reactive({
list:[]
})
const route = useRoute()
let id = computed(() => route.query.id);
// 获取演员图片列表数据
onMounted(async () => {
let data = await service.get(configapi.actors(id.value))
detailData.list = data.directors.concat(data.actors)
});
return {
detailData,
title
}
}
其主要业务逻辑如下:
-
获取演员图片列表数据。
-
将 title 从 Vuex 的 Store 中取出来并展示。
电影评论信息组件
在 detail 目录下新建 moviecomments.vue,用来作为电影评论列表组件,其核心代码如下:
setup(){
const store = Vuex.useStore()
// 从Vuex的Store中获取title
const title = computed(() => store.state.detailTitle);
// 获取用户自己发票的评论数据
const incommentList = computed(() => store.state.commentList);
let detailData = reactive({
list:[]
})
const route = useRoute()
// 从url上获取id参数
let id = computed(() => route.query.id);
onMounted(async () => {
let data = await service.get(configapi.comments(id.value),{
start:0,
count:20
})
// 将后端获取的数据和用户发票的数据进行组合
detailData.list = incommentList.value.concat(data.reviews || [])
});
return {
detailData,
title
}
}
其主要业务逻辑如下:
-
根据 url 上的参数 id 获取评论列表数据。
-
根据数据渲染并展示评论列表。
-
当有用户自己发表的数据时,将数据进行合并。
在该组件中,单击发表评论跳转到发表界面。