# 影视详情页
# 介绍
影视详情页面是本项目中功能最多的页面,包含了多个组件与子页面。
# 目录结构
└─ src
└─ views
└─ movie # 影视
└─ detail # 详情
├─ index # 入口文件夹
│ ├─ components # 组件
│ │ ├─ MovieAward.vue # 获得奖项
│ │ ├─ MovieBar.vue # 底部工具栏
│ │ ├─ MovieExtra.vue # 影视更多资料
│ │ ├─ MovieInfo.vue # 顶部影视主要信息
│ │ ├─ MovieRating.vue # 评分展示栏
│ │ ├─ PhotoWall.vue # 相册栏
│ │ ├─ SerialRow.vue # 系列
│ │ └─ Skeleton.vue # 骨架屏
│ ├─ detail.vue # 详细信息子页面
│ ├─ favorite.vue # 收藏列表子页面
│ └─ index.vue # 详情入口页面
├─ cast # 演员表
├─ article # 文章资讯
├─ company # 出品发行公司
├─ award # 荣获奖项
├─ dialogue # 经典台词
├─ knowledge # 幕后知识
├─ rating # 评分页面
│ ├─ components # 评分组件
│ │ ├─ RateDetail.vue # 评分详情
│ │ └─ RateTrend.vue # 评分趋势
│ ├─ create.vue # 用户评分
│ └─ index.vue # 评分分布
├─ pubdate # 各地上映日期
├─ level # 家长引导等级
├─ review # 影评列表
├─ role # 角色表
├─ serial # 系列列表
└─ video # 视频列表
# 头部
header
部分主要使用了全局组件 heade-scroll-bar
,其中插槽部分使用了自定义内容,详情请查看 heade-scroll-bar 使用文档。
# 页面缓存
由于详情页面有多个详细分类页面,为优化加载速度,对详情页做了 keep-alive
处理。该 keep-alive
在 App.vue
中设置。
<div id="app">
<keep-alive include="Layout,MovieDetail">
<router-view />
</keep-alive>
</div>
当页面被 keep-alive
时,当路由地址变更,但路由名称未变更时,如在该详情页点击 相似影视
时,路由名称未变,不会触发 activated
生命周期,此时需要在 watch
中监听路由地址的变化,当路由地址中的 id
变更时,则触发获取影视详情的接口 this.getMovie()
,且页面需要滚动到顶部。
# 页面优化
为优化详情页的展示速度,当用户在其它影视列表页面点击进入详情时,会将列表中该影视信息存入到 vuex
中,当然,列表中只是影视的部分信息,对应为详情的 movie-info
部分。
进入详情后,会先从 vuex
中获取该影视的信息,如果不存在(vuex
中不存在或者其影视 id
与详情页路由 id
不匹配),则会全屏显示骨架屏,否则 movie-info
部分不显示骨架屏。
getMovie
方法获取到影视详情后,会存入 vuex
中,以便用户刷新页面,或者离开再次进入该页面,能够立即加载本地数据,减少用户等待。
# 加载动画
详情页存在多个子页面,其存在两种过渡动画,一种是 layer
从下向上弹出的抽屉式,一种是 slide-left
从右向左的翻页式。
在 transform
中,将 name
根据路由变化,动态赋值,以满足不同的加载方式。
<transition :name="transition">
<router-view
:movie="movie"
:loading="loading"
@ratingChange="ratingChange"
@favorite-update="favoriteUpdate"
/>
</transition>
// 路由更新前,根据前往的页面不同,使用不同的过渡动画
beforeRouteUpdate(to, from, next) {
// 使用 layer 的路由名称
const layerRouters = [
"MovieFavorite",
"MovieDetail",
"MovieRating",
"MovieRatingCreate",
"MovieComment",
];
// 将访问的路由名称
if (layerRouters.includes(to.name)) {
this.transition = "layer";
} else {
this.transition = "slide-left";
}
// 执行 next() 方法,路由才会跳转
next();
},
过渡动画样式文件,写在了 App.vue
文件中,以便全局使用
.layer-enter-active, .layer-leave-active {
transition: all 0.3s;
}
.layer-enter, .layer-leave-to {
transform: translateY(100%);
}
.slide-left-enter-active, .slide-left-leave-active {
transition: all 0.3s;
}
.slide-left-enter, .slide-left-leave-to {
transform: translateX(100%);
}
# 剧情介绍
剧情介绍使用子页面实现,关于子页面自定义底部,请查看全局组件 page
文档与源码。
# 演员页
演员表有演员分类,分类标题有滚动吸顶效果。
本项目中使用 position: sticky;
样式实现,该属性目前兼容性已经很高。
# 影评页
由于影评页面是从右向左展示的子页面,当页面还在动画过渡中时,接口请求返回数据了,页面大数据量渲染,阻塞渲染进程,会导致过渡动画掉帧,所以在过渡动画中时,先不加载数据,等过渡动画结束,再加载数据。
loadMore() {
// 使用 isFirst 标志位来处理是否为首次加载
if (this.page === 1 && this.isFisrt) {
setTimeout(() => {
this.isFisrt = false;
this.getData(getMovieReviews, this.id);
}, 200);
} else {
this.getData(getMovieReviews, this.id);
}
}