加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

day82:luffy:课程详情页面显示&章节和课时显示&视频播放

发布时间:2020-12-20 09:58:58 所属栏目:Python 来源:网络整理
导读:目录 1.初始课程详情页面 2.视频播放组件 3.课程详情页面后端接口实现 4.课程详情页面-前端 5.CKEditor富文本编辑器 6.课程章节和课时显示-后端接口 7.课程章节和课时显示-前端 1.初始课程详情页面 1.Detail.vue !-- 课程详情页面初始页面 -- template div c

目录

1.初始课程详情页面

2.视频播放组件

3.课程详情页面后端接口实现

4.课程详情页面-前端

5.CKEditor富文本编辑器

6.课程章节和课时显示-后端接口

7.课程章节和课时显示-前端

1.初始课程详情页面

1.Detail.vue

<!-- 课程详情页面初始页面 -->
<template>
    div class="detail">
      Vheader/>
      ="main">
        ="course-info">
          ="wrap-left">

          </div="wrap-right">
            h3 ="course-name">flaskh3p ="data">111人在学&nbsp;&nbsp;&nbsp;&nbsp;课程总时长:111课时/12小时&nbsp;&nbsp;&nbsp;&nbsp;难度:p="sale-time">
              ="sale-type">限时免费="expire">距离结束:仅剩 01天 04小时 33分 span ="second">08span>="course-price">活动价="discount">¥0.00="original">¥1111="buy"="buy-btn">
                button ="buy-now">立即购买button="free">免费试学="add-cart"><img src="/static/img/cart-yellow.svg" alt="">加入购物车="course-tab"ul ="tab-list"li :class="tabIndex==1?'active':''" @click="tabIndex=1">详情介绍li="tabIndex==2?'active':''"="tabIndex=2">课程章节 ="tabIndex!=2?'free':''">(试学)></="tabIndex==3?'active':''"="tabIndex=3">用户评论 (42)="tabIndex==4?'active':''"="tabIndex=4">常见问题ul="course-content"="course-tab-list"="tab-item" v-if="tabIndex==1"="course-brief" v-html="tabIndex==2"="tab-item-title"="chapter">课程章节="chapter-length">共11章 147个课时="chapter-item"="chapter-title"="/static/img/1.png">第1章·Linux硬件基础="lesson-list">
                  ="lesson-item">
                    ="name"="index">1-1> 课程介绍-学习流程>免费="time">07:30 ="/static/img/chapter-player.svg"="try">立即试学>1-2> 服务器硬件-详解>第2章·Linux发展过程>2-1> 操作系统组成-Linux发展过程>2-2> 自由软件-GNU-GPL核心讲解="tabIndex==3">
              用户评论
            ="tabIndex==4"
              常见问题
            ="course-side">
             ="teacher-info">
               h4 ="side-title">授课老师h4="teacher-content">
                 ="cont1">
                   >
                     ="teacher-name">xxx="teacher-title">ssss="narrative" >kkkkFooter/>
    >
>

script>
import Vheader from "./common/Vheader
import Footer from ./common/Footer



export default {
    name: Detail,data(){
      return {
        tabIndex:1style scoped
.main{
  background: #fff;
  padding-top 30px;
}
.course-info
  width 1200px
  margin 0 auto
  overflow hidden
.wrap-left
  float left 690px
  height 388px
  background-color #000
.wrap-right
  position relative
.course-name
  font-size 20px
  color #333
  padding 10px 23px
  letter-spacing .45px
.data
  padding-left 23px
  padding-right
  padding-bottom 16px 14px #9b9b9b
.sale-time 464px #fa6240 #4a4a4a
.sale-type  .36px
.sale-time .expire right
.sale-time .expire .second 24px
  display inline-block #fafafa #5e5e5e 6px 0
  text-align center
.course-price 5px 23px
.discount 26px
  margin-left 10px
  margin-bottom -5px
.original
  text-decoration line-through
.buy 0px 23px absolute
  left 0
  bottom
.buy .buy-btn
.buy .buy-now 125px 40px
  border #ffc210
  border-radius 4px
  cursor pointer
  margin-right 15px
  outline none
.buy .free 1px solid #ffc210
.add-cart
  margin-top
.add-cart img 18px 7px
  vertical-align middle

.course-tab
    width 100%
    background
    margin-bottom
    box-shadow 0 2px 4px 0 #f0f0f0;


.course-tab .tab-list
    margin auto
    color
    overflow
.tab-list li
    float
    margin-right
    padding 26px 20px 16px
    font-size 17px
    cursor
.tab-list .active
    border-bottom 2px solid #ffc210
.tab-list .free #fb7c55
.course-content #FAFAFA
    padding-bottom
.course-tab-list 880px
    height
    box-sizing border-box
    position
.tab-item
.tab-item-title
    justify-content space-between 25px 20px 11px
    border-radius 1px solid #333
    border-bottom-color rgba(51,51,.05)

.chapter
.chapter-length
    letter-spacing .19px
.chapter-title .26px 12px #eee 2px
    display -ms-flexbox flex
    -ms-flex-align
    align-items
.chapter-title img
    vertical-align
.lesson-list0 20px
.lesson-list .lesson-item 15px 20px 15px 36px
.lesson-item .name #666
.lesson-item .index 5px
.lesson-item .free 100px 1px 9px
    margin-left
.lesson-item .time .23px
    opacity 1
    transition all .15s ease-in-out
.lesson-item .time img text-bottom
.lesson-item .try 86px 28px
    right
    top all .2s ease-in-out
    outline
    border
.lesson-item:hover #fcf7ef 0 0 0 0 #f3f3f3
.lesson-item:hover .name
.lesson-item:hover .try

.course-side 300px
.teacher-info
.side-title
    font-weight normal 18px 14px
.side-title span
    border-left
    padding-left

.teacher-content 30px 20px

.teacher-content .cont1

.teacher-content .cont1 img 54px
.teacher-content .cont1 .name
.teacher-content .cont1 .teacher-name 188px
.teacher-content .cont1 .teacher-title 13px
    white-space nowrap
.teacher-content .narrative
    line-height}
style>
初始课程详情页面

2.index.js注册组件

import Detail from "@/components/Detail"
{
    path:'/course/detail/:id',// 前端页面动态路由匹配
    component:Detail  
}

 :id ===> this.$route.params.id  // course/detail/1

3.course.vue

实现:在课程列表页面点击不同的课程可以进入到不同的课程详情页面

router-link :to="'/course/detail/'+course.id+'/'">django基础知识router-link> ="/static/img/avatar1.svg">5000人已加入学习>
           

此时 点击可进入课程详情页面

2.视频播放组件

1.安装

npm install vue-video-player --save

2.main.js注册组件

 main.js

require('video.js/dist/video-js.css');
require('vue-video-player/src/custom-theme.css');
import VideoPlayer from 'vue-video-player'
Vue.use(VideoPlayer);

3.Detail.vue引入

HTML部分

 html >
     videoPlayer ="video-player vjs-custom-skin"
                  ref="videoPlayer"
                  :playsinline="true"
                  :options="playerOptions"
                  @play="onPlayerPlay($event)" 
                  @pause="onPlayerPause($event)">

     videoPlayer>

JS部分

 js
import {VideoPlayer} from 'vue-video-player'
data(){
    return{
        ...
         playerOptions: {
              playbackRates: [0.7,1.0,1.5,2.0],1)"> 播放速度
              autoplay: false,1)"> 如果true,则自动播放
              muted:  默认情况下将会消除任何音频。
              loop:  循环播放
              preload: 'auto',1)"> 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
              language: 'zh-CN' 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
              fluid: true,1)"> 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
              sources: [{  播放资源和资源格式
                type: "video/mp4" 你的视频地址(必填)
              }],poster: "",1)"> 视频封面图
              width: document.documentElement.clientWidth,1)"> 默认视频全屏时的最大宽度
              notSupportedMessage: '此视频暂无法播放,请稍后再试',1)"> 允许覆盖Video.js无法播放媒体源时显示的默认信息。
        }
        
    }
    
    }

    
    method:{
        ...
         视频播放时触发此函数
        onPlayerPlay:{
            ...
        }
         视频暂停时触发此函数
        onPlayerPause:{
            ...
        }
    }
components:{
    ...
    videoplayer  挂载一下视频播放组件
}

4.在Xadmin上传视频

注意:课程详情页的那些视频其实要存到数据库里的,但是数据库并没有课程视频这个字段

所以需要在course表中添加一个course_video字段

# 将上传的视频保存在本地的video文件夹中
course_video = models.FileField(upload_to='video',verbose_name=封面视频
python3 manage.py makemigrations
python3 manage.py migrate

在xadmin上传视频,即可在前端页面看到自己上传的视频

3.课程详情页面后端接口实现

接下来做的事情:在课程表里已经有了我们视频数据了,现在我们要想办法写一个后端接口将真实的课程详情数据返回到页面上,把真实的视频播放路径给前端,让前端展示出来。把真实的图片路径或者视频路径给前端,前端加载的时候会往后端发请求获取地址对应的视频数据,然后进行播放就可以了

urls.py

urlpatterns = [
    ......
    re_path(rdetail/(?P<pk>d+)/'
 CourseDetailView(RetrieveAPIView):
    queryset = models.Course.objects.filter(is_deleted=False,is_show=True)
    serializer_class = CourseDetailModelSerializer

models.py

 Course(BaseModel):
    ......
    level_choices = (
        (0,初级),(1,中级高级"难度等级")
    
    ......
    

    def level_name(self):
        '''level字段默认显示的是数字,通过返回get_字段_display可以返回数字对应的名字'''
        return self.get_level_display()

serializers.py

 CourseDetailModelSerializer(serializers.ModelSerializer):
     序列化器嵌套
    teacher = TeacherModelSerializer()   将外键关联的属性指定为关联表的序列化器对象,就能拿到关联表序列化出来的所有数据,还需要在fields中指定一下,注意,名称必须和外键属性名称相同

     Meta:
        model = models.Course
        fields = [id",1)">namecourse_imgstudentslessonspub_lessonspriceteacherlevel_namecourse_video] 
        
        

后端接口测试

drf后端接口测试 /course/detail/1 可得到course=1所需要的所有数据

?

4.课程详情页面-前端

1.注意点

在课程列表页面,我们只展示了四个课时。但是在课程详情页我们要展示所有课时,所以不能用之前那个序列化器了。

现在我们是需要所有章节和所有课时信息、老师信息和课程信息。

如果将所有的信息都定义到一个序列化器的字段中,数据量有些太大。

我们可以利用axios可以发送异步请求的这个特点,分成两次请求来获取数据

将章节信息和课时信息放在一个序列化器中

其它的放在另一个序列化器中

我们先去请求除了章节信息和课时信息的其他信息

现在后端数据已经准备好了,接下来就是前端发送axios请求获取数据了

2.Detail.vue

-->
 >{{ course_data.name }}>{{course_data.students}}人在学&nbsp;&nbsp;&nbsp;&nbsp;课程总时长:{{course_data.lessons}}&nbsp;&nbsp;&nbsp;&nbsp;难度:{{course_data.level_name}}>¥{{course_data.price}}>


 老师部分 >{{course_data.teacher.name}}>{{course_data.teacher.title}}>{{course_data.teacher.signature}} 视频播放 
                 ref
                 :playsinline
                 :options
                 @play
                 @pause>
前端将从后段获取的数据展示出来-HTML

 js

<script>

export default {
    name: "Detail" {
       ......
        course_id:0 播放资源和资源格式
            type: "video/mp4"          }],1)"> 视频封面图
          ......

    },created(){
      this.get_course_id();
      .get_course_data();
    },methods: {
    
       获取课程id,用处是请求不同的课程详情页面数据时带上不同的url参数来请求不同的课程详情数据
      get_course_id(){
        this.course_id = .$route.params.id;
         可以判断course_id的合法性 todo
      },get_course_data(){
        this.$axios.get(`${this.$settings.Host}/course/detail/${this.course_id}/`)
        .then((res)=>{
          this.course_data = res.data;  获取课程详情页数据
          this.playerOptions.sources[0].src = res.data.course_video;  获取视频数据
          this.playerOptions.poster = res.data.course_img  获取视频封面数据

        })
      },},}
</script>
前端发送axios请求获取后端数据-JS

5.CKEditor富文本编辑器

1.安装

pip install django-ckeditor

2.settings/dev.py INSTALLAPP配置

INSTALLED_APPS = [
    ...
    ckeditor 富文本编辑器
    ckeditor_uploader 富文本编辑器上传图片模块
    ...
]

3.setting/dev.py 配置

 富文本编辑器ckeditor配置
CKEDITOR_CONFIGS = {
    default: {
        toolbar': full 工具条功能,full表示全部,Basic表示基本功能,功能少很多,还有个Custom自定义功能选项
        height': 300,1)"> 编辑器高度
         'width': 300,# 编辑器宽
    },}
CKEDITOR_UPLOAD_PATH = ''   上传图片保存路径,留空则调用django的文件上传功能



 也可以自定义配置
CKEDITOR_CONFIGS =Customtoolbar_Custom: [
            [BoldItalicUnderlineImage'],1)"> 通过浏览器f12来查看每个功能的标签,就看到了类值cke_button_工具名称[注意使用驼峰式来写]
            [NumberedListBulletedList-OutdentIndentJustifyLeftJustifyCenterJustifyRightJustifyBlock],[LinkUnlinkRemoveFormatSource]
        ]
    }
}

4.在总路由lyapi/urls.py添加路由

path(r^ckeditor/ckeditor_uploader.urls')),

5.将brief字段升级

 course/models.py
from ckeditor_uploader.fields import RichTextUploadingField
 Course(models.Model):
    
     课程概述变为富文本编辑器显示
    brief = RichTextUploadingField(max_length=2048,1)">课程概述True)
    

6.brief图片路径转化问题

相对路径转化为绝对路径

在brief中,存放的都是一些各种标签组成的字符串,而用户在使用富文本编辑器时,有可能会使用上传图片的功能。而图片上传后,默认都存在了后端的media文件夹中。但是前端并不会将我们的后端地址识别出来。它会默认被存放到前端:www.lycity.com/media中,所以需要我们手动更改一下上传图片存储的路径。这样用户上传的图片才能显示出来。

models.py

# course/models.py
 Course:
    ...
     new_brief(self):
        data = self.brief
        server_addr = contains.SERVER_ADDR
        data = data.replace(/media{server_addr}/media)
         data
        

settings/constants.py

SERVER_ADDR = http://www.lyapi.com:8001'

serializers.py

 CourseDetailModelSerializer:
    ...
    teacher = TeacherModelSerializer()
     model.Course
        fields = [.........,teacher,level_name,new_brief]  将new_brief添加到字段中
        
        

7.表情和图片应用不同的CSS样式

 contains.SERVER_ADDR
        
        做了两件事:
        1.将用户上传图片的相对路径改成了绝对路径
        2.让图片和表情应用不同的CSS样式
        '''
        data = data.replace(src="/mediaclass="img_xx" src="{server_addr}/mediareturn data

6.课程章节和课时显示-后端接口

urls.py

re_path(rchapter/
from django_filters.rest_framework  DjangoFilterBackend
 ChapterView(ListAPIView):
    queryset = models.CourseChapter.objects.filter(is_deleted=False,1)">True)
    serializer_class = CourseChapterModelSerializer
    filter_backends = [DjangoFilterBackend,]
    filter_fields = (course
 CourseLessonModelSerializer:
     models.CourseLesson
        fields = [section_linkdurationfree_traillesson]


 CourseChapterModelSerialzer:
    
    在一的序列化器嵌套多的序列化器,切记要加参数many=True
    coursesection = CourseLessonModelSerializer(many=True)  1201
    
     models.CourseChapter
        fields = [chapter]
        

drf测试接口:course/chapter/?course=1

7.课程章节和课时显示-前端

>共{{chapter_data.length}}章 ="chapter-item" v-for="(chapter,chapterindex) in chapter_data">第{{chapter.chapter}}章·{{chapter.name}}="lesson-item"="(lesson,lesson_index) in chapter.coursesections">{{chapter.chapter}}-{{lesson.lesson}}> 课程介绍-{{lesson.name}}v-show="lesson.free_trail" class>{{lesson.duration}} ="try"="lesson.free_trail" v-else>立即buy>

                >
课程章节和课时显示-HTML

 js
export  {
        
        chapter_data:{},}

    },created(){
  
      .get_chapter_data();
    },methods: {

     
      
      get_chapter_data(){
        this.$settings.Host}/course/chapter/`,{
          params:{
            course:.course_id,}
        }).then((res)=>{
          console.log(res.data);
          this.chapter_data = res.data
        })
      },}
课程章节和课时显示-JS

?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读