yb课堂 视频详情页模块开发《三十八》
CourseDetail基础模块开发
CourseDetail模块开发,拆分组件
- CourseDetail.vue
- Header.vue
- Course.vue
- Tab.vue
- Summary.vue
- Calalog
创建文件夹
CourseDetail开发
<template> <div> <!--视频顶部组件--> <detail-header :videoInfo="videoInfo"></detail-header> <!-- 视频详情组件 --> <detail-course :videoInfo="videoInfo"></detail-course> <!--视频tab简介组件--> <detail-tab :videoInfo="videoInfo" :chapterList="chapterList"></detail-tab> <!--底部立即购买--> <footer> <router-link :to="{path:'/pay',query:{video_id:this.$route.query.video_id}}" class="user_buy"> <button>立刻购买</button> </router-link> </footer> </div> </template> <script> //引入组件 import DetailHeader from "./Components/Header"; import DetailCourse from "./Components/Course"; import DetailTab from "./Components/Tab"; import { getVideoDetail } from "@/api/getData.js"; export default { //注册组件 components: { DetailHeader, DetailCourse, DetailTab }, data() { return { //视频信息 videoInfo: {}, chapterList: [] }; }, methods: { //获取视频详情 async getDetail(vid) { try { const result = await getVideoDetail(vid); if (result.data.code == 0) { this.videoInfo = result.data.data; this.chapterList = result.data.data.chapter_list; } } catch (error) { console.log(error); } } }, mounted() { //渲染之后拿到数据 this.getDetail(this.$route.query.video_id); console.log(this.$route.query.video_id); } }; </script> <style lang="scss" scoped> //底部 footer { // fixed固定在底部 position: fixed; bottom: 0; width: 100%; padding: 8px 0; background-color: #fff; z-index: 999; box-shadow: 0 -2px 4px 0 rgba(0, 0, 0, 0.05); } //设置购买按钮样式 button { display: block; color: #fff; margin: 0 auto; background-color: #d93f30; height: 34px; line-height: 34px; border-radius: 17px; width: 80%; border: none; font-size: 15px; text-align: center; } </style>
Header开发
<template> <div> <header> <div class="header"> <span @click="$router.back(-1)"><i class="cubeic-back"/></span> <div class="title"> {{videoInfo.title}} </div> </div> </header> </div> </template> <script> export default { props: { videoInfo: { type: Object, required: true } } }; </script> <style lang="scss" scoped> .header { display: flex; //flex左右布局 background-color: #07111b; padding: 10px 20px; color: #fff; } // 返回箭头 .cubeic-back { color: #fff; margin-right: 5px; } //视频标题 .title { font-size: 16px; width: 80%; //超出省略 text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } </style>
Summary开发
<template> <div> <img class="summary" :src="videoInfo.summary" /> </div> </template> <script> export default { props: { videoInfo: { type: Object, required: true } } }; </script> <style lang="scss" scoped> .summary { width: 100%; padding-bottom: 50px; margin: 15px 0; } </style>
Course开发
<template> <div class="c_wapper"> <div class="course"> <div class="l_img"> <img :src="videoInfo.cover_img" :title="videoInfo.title"/> </div> <div class="r_txt"> <div class="txt"> <span>综合评分:</span> <p>{{videoInfo.point}}</p> </div> <div class="txt"> <span>价格:</span> <p>¥{{videoInfo.price/100}}</p> </div> </div> </div> </div> </template> <script> export default { //从父组件传值 props: { videoInfo: { type: Object, required: true } } }; </script> <style lang="scss" scoped> //包裹层 .c_wrapper { padding: 0 14px; } //视频信息包裹层 .course { margin: 14px 0; display: flex; //设置flex,左右布局 } //视频左边图⽚层 .l_img { height: 88px; margin-right: 14px; & img { height: 100%; border-radius: 15px; } } // 视频右边⽂字包裹层 .r_txt { padding: 6px 0; font-size: 12px; flex: 1; //设置1可⾃动伸缩占⽤剩余空间 } //每⾏⽂字层(综合评分、价格) .txt { // 设置flex让⽂字两端对⻬ display: flex; justify-content: space-between; line-height: 16px; & p { text-align: center; width: 40%; color: #3bb149; } & i { color: #666; font-weight: bolder; width: 60%; & span { color: #2b333b; font-size: 12px; } } } </style>
tab动态组件开发
不同组件之间的动态切换:https://cn.vuejs.org/v2/guide/components-dynamic-async.html
组件的过渡:https://cn.vuejs.org/v2/guide/transitions.html#ad
Tab开发
<template> <div> <cube-tab-bar v-model="selectedLabel" show-slider> <cube-tab v-for="item in tabs" :label="item.label" :key="item.label"> </cube-tab> </cube-tab-bar> <component :videoInfo="videoInfo" :chapterList="chapterList" :is='selectedLabel==="简介"?"Summary":"Catalog"'> </component> </div> </template> <script> import Summary from "./Summary"; import Catalog from "./Catalog"; export default { components: { Summary, Catalog }, props: { videoInfo: { type: Object, required: true }, chapterList: { type: Array, required: true } }, data() { return { selectedLabel: "简介", tabs: [ { label: "简介" }, { label: "目录" } ] }; } }; </script>
Catalog开发
<template> <div class="cate_box"> <div> <ul class="content" v-for="(item,index) in chapterList" :key="item.id"> <h1>第{{index+1}}章 {{item.title}}</h1> <li class="sub_cate" v-for="(subitem,subindex) in chapterList[index].episode_List" :key="subitem.id"> <span class="sub_title">{{index+1}}-{{subindex+1}} {{subitem.title}}</span> </li> </ul> </div> </div> </template> <script> export default { props: { chapterList: { type: Array, required: true } } }; </script> <style lang="scss" scoped> // ⽬录包裹层设置边距 .cate_box { padding: 0 15px 50px; background-color: #fff; margin: 15px 0; } //每⼀章包裹层 .content { padding: 10px; // 章标题 & h1 { font-size: 16px; width: 100%; margin-bottom: 15px; font-weight: bolder; // 设置章标题过⻓,超过⾏宽度省略隐藏 text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } } //集包裹层 .sub_cate { font-size: 12px; padding: 10px 0; //集标题 .sub_title { // 设置集标题过⻓,超过⾏宽度省略隐藏 display: block; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } } </style>