某在线视频播放小程序项目总结

1,148 阅读12分钟

某在线视频播放小程序项目总结

1.项目简介

一款为家庭用户设计的实用技能学习平台,在tv端和小程序端都可以通过平台选择感兴趣的视频进行学习,小程序端主要功能包括3个tabBar:

  • 视频分类展示
  • 我的课程:最近学习课程、已有课程、收藏课程
  • 个人账号管理:同步电视学习、意见反馈等

2. 主要工作和疑难点汇总

2.1 主要工作

  1. 封装api请求,改造wx.requeset方法,封装http请求
  2. 抽取公共样式文件,在每个page文件夹的.wxss文件中,通过import 引入, 如:@import "../../lib/base.wxss";
  3. 抽取公共组件,如底部分享组件、弹框组件,通过在各个页面配置usingComponents参数使用。
  4. 封装全局公共函数
  5. 业务逻辑

2.2 疑难点汇总

  1. 怎么保存学习记录?
  2. 怎么获取上次学习记录?
  3. 怎么创建订单?
  4. 怎么支付订单?
  5. 分享给第三人,点击如何跳转到分享的精确页面?
  6. 购买的课程列表、收藏的课程列表,从哪里拿到?
  7. 最近学习列表?这个是怎么拿到的?
  8. 如何区分是课程一级列表,还是二级列表?
  9. 跳转到课程详情页有哪些信息?
  10. sso_token 和 token 有什么不同?
  11. 为什么不支持ios下购买?
  12. 什么时候会同步电视端课程?
  13. 绑定电视账号后,如何跳转到之前的页面?
  14. 如何第一次只返回第一页,下拉分页,获取更多视频列表?
  15. swiper组件的使用
  16. top箭头何时出现?出现了如何返回顶部?
  17. 如何获取平台类型?
  18. 如何客服通话?
  19. 视频分类tab怎么做的?
  20. 如何使用canvas生成海报?
  21. 可操作区域高宽和屏幕高宽?
  22. 当前视频播放完毕如何自动播放下一个视频?
  23. onPullDownRefresh 和 onReachBottom

3. 业务逻辑梳理

  1. 项目哪几个page组成?有几个组件?
9个page 1个组件
login 获取token、管理跳转
le_login 同步账号
my 个人账号管理,账号绑定、消息、关于、意见反馈
index 首页
list 视频分类页
detail 视频详情页
my-detailbox 视频详情页,底部分享组件
play 视频播放页面、咨询页面
topic 专题列表页
curriculum 我的课程页面
重点:play(咨询、播放逻辑)、detail

2.login:微信授权登陆

login模块做了哪些工作? 
  1. onLoad 的时候,如果是分享进入,获取分享所在的页面路径,课程分类和课程id。判断是否有权限,getUserInfo 。拿到平台信息,ios还是安卓,getSystemInfo。

    //onLoad中:为什么需要场景值?用于分享,第三人登陆使用
    this.setData({
      isOnLoad:1,
      sharePage:e.page || '',
      shareId: e.id || '',
      scene:decodeURIComponent(e.scene) || '',   // 场景值
      course_item_id:e.course_item_id || '',   //课程类目id
      course_id:e.course_id || '',   // 课程id
      sso_token:e.sso_token || '',   // 电视端token
      isbind:e.isbind || 0,          // 是否绑定电视
    })
    
  2. 发送登陆请求,拿到 token, is_bind_sso, openid 等值

    每个用户的token不一样
    
  3. 处理页面跳转逻辑

     通过解析 onLoad:(e) 场景值 e.scene,判断页面来源,从而做进一步跳转
    
  4. 同步电视端账号,学习记录,

     第一种情况,有电视账号,但是和当前绑定的不一致,绑定新信息
     if(that.data.sso_token && app.globalData.is_bind_sso==1 && that.data.isbind==0){}
     
     第二种情况,没绑定过电视账号
     if(that.data.sso_token && that.data.isbind==0){}
    

3.global中几个参数, 干嘛的

globalData: {
    userInfo: null,
    openid:'',
    token:"", //微信token  2a35196268e335fbd3915d1ba14212b7
    sso_tk:"", //电视端账号 token
    is_bind_sso:"0", //是否绑定电视端账号,0未绑定,1绑定
    platform:"android" //平台
},

4.可以改进的地方:

弹框可以抽成全局函数,弹框成功、弹框失败、loading弹框
抽取全局公共样式

index页面,可以做成8个icon可以总成组件
list和ranking页面,有重复的部分,视频卡片信息,可以抽取出来,做成组件

5.首页数据怎么出来的?

head 轮播课程, 头部固定位
categorys 8个icon, 一级分类列表
modules 运营模块列表
ranking 每日精选(课程点播排行榜)10个

6.le-login 页面干嘛的?

  1. onLoad时候获取图片验证码,记录from值,上一个页面可能是同步页面,也可能是视频详情页面,记录course_id

  2. 验证手机号

  3. 点击切换图片验证码

  4. 点击获取验证码,60秒后重新获取

    me.data.timer = 60; me.data.timerFun = setInterval(function () { if (me.data.timer > 0) { me.setData({timer:me.data.timer-1}) }else { me.setData({timer:'重新发送'}) clearInterval(me.data.timerFun); } }, 1000);

  5. 登陆

     发送请求登陆
    

7.my 页面干嘛的

1. 跳转消息列表页,这里也是用到了onReachBottom方法,页面上拉触底事件的处理函数  
2. 跳转到意见反馈页面,open-type="contact"  
3. 绑定电视账号  

8.index 页面干嘛的

8.1 首页数据是怎么出来的?  
head 轮播课程, 头部固定位
categorys 8个icon, 一级分类列表
modules 运营模块列表
ranking 每日精选(课程点播排行榜)返回10个排名最高的视频

8.2 swiper组件的使用

//假如只有一个视频,不能使用swiper,假如有多个视频,可以使用swiper
	<view class="v-swiper">
    <swiper circular="true" indicator-dots="{{indicatorDots}}" indicator-color="rgba(0,0,0,0.15)" indicator-active-color="#ffffff" autoplay="true" interval="{{interval}}" duration="{{duration}}">
        <block wx:for="{{banner}}">
            <swiper-item>
                <image  src="{{item.zone_image}}" mode="widthFix" class="slide-image" data-action="{{item.action}}" data-courseid="{{item.ext.course_id}}" data-categoryid="{{item.ext.category_id}}" bindtap="gotoPage" />
            </swiper-item>
        </block>
    </swiper>
</view>

8.3 点击跳转至二层页面

根据点击目标对象的action值进行跳转,  
event.currentTarget.dataset.action==6

8.4 下拉显示更多视频

onReachBottom 函数

8.5 一键返回顶部

9.list页面做了什么

9.1视频的二级tab,如生活信息、情感心理
    可滚动视图区域。使用scroll-view 组件。
9.2视频卡片信息列表
	和首页的一样,可以抽出来做组件。

10.detail页面做了什么?

10.1 展示视频相关信息

onLoad获取可使用窗口高宽,做什么?  
wx.getSystemInfo,返回参数,windowsHeight和windowWidth。 

为什么不用屏幕高宽?    
可操作区域的宽高就用windowsHeight和windowWidth。

10.2 课程介绍、课程评论、课程列表

课程介绍和课程列表是,onLoad的时候直接返回拿到的。
课程列表,通过onLoad发送请求,返回数组获取,videoList。

课程评论是,点击tab,发送请求获取的,会有个loading效果,返回评论列表
课程评论只能评论一条,类似购物评价,此次评论成功后,将不可再次评论。

10.3 点击可播放视频,跳转到视频播放页面

wx.navigateTo({
    url: '../play/play?type=list&course_item_id='+ ids 
    +'&course_id=' + event.currentTarget.dataset.id
})

10.4 咨询、收藏、分享、分享到朋友圈 ,是一个底部分享组件,my-detailbox , 在detail页面和play页面都用到了。

//分享功能,跳转到login页面,
<button open-type='share' class="shareBtn" wx:if="{{item.id=='share'}}">
	<block>
		<image class="nav-image"  src="{{item.image}}"></image>
	</block>
</button>
        
        
onShareAppMessage:function(res){
    var me = this;
    return {
     	path: 'pages/login/login?scene=detail-' + me.data.intro.course_id,
     	success: function (res) {
     	},
     	fail: function (res) {
     	}
   }
}

10.5 收藏课程

10.6 如何关闭生成的画报?

整个背景做成蒙版效果,位置fixed, top:0, left:0, width: 100%
点击,将视图可见设为false,点击不是画报的任何区域,关闭画报

10.7 如何保存生成的图片

wx.canvasToTempFilePath


canvasToImage:function(){
var me = this
wx.canvasToTempFilePath({
    x: 0,
    y: 10,
    //指定的画布区域的宽度
    width: me.data.windowWidth-60,
    height: (me.data.pengyouquan_layerHeight-20),
    
    //输出的图片的宽度,width*屏幕像素密度
    destWidth: (me.data.windowWidth-60) * 2,
    destHeight:(me.data.pengyouquan_layerHeight-20) * 2,
    canvasId: 'myCanvas',
    success: function (res) {
        wx.saveImageToPhotosAlbum({
          filePath: res.tempFilePath,
        })
        wx.showModal({
          title: '成功保存图片',
          showCancel: false,
          content: '图片已保存到手机相册,请自行前往朋友圈分享',
          confirmText: "知道了",
          success (res) {}
        })
    },
    fail: function (err) {
        console.log('失败')
        console.log(err)
    }
})
},

10.8 处理视频时长函数

MillisecondToDate
使用场景: 返回的课程视频列表,视频长是秒为单位的,展示是 时:分:秒

10.9 购买成功处理函数

getDetailDate	

11.组件detailbox 详情

11.1 怎么创建订单?

安卓手机可以通过小程序点击购买

11.2 如何支付?

如果没有绑定电视账号,首先绑定电视账号

调用后端请求,在成功的回调函数中,调用
wx.requestPayment
支付成功后,detail 页面重新获取新的课程数据

11.3 如何咨询?

首先跳转到play页面,goChat函数

11.4 图标

返回列表,返回会话顶部,返回会话底部

12.play 页面

12.1 视频播放组件

// initial-time 指定视频初始播放位置
// bindtimeupdate 播放进度变化时触发,
//bindended 当播放到末尾时触发 ended 事件

<video class="video" id="video{{currentVideoId}}" 
src="{{video_info.video_cdn}}" initial-time="{{video_info.last_play_pos/1000}}" 
autoplay="{{autoplay}}" controls="true" bindended='bindend' 
bindtimeupdate="bindtimeupdate"></video>

12.2 咨询,建立一个全局 connectSocket

if(!me.data.isSocket){
  wx.getSystemInfo({
    success: function(res) {
      me.setData({model:res.model});
      me.socket(res.model); //设备型号
    },
  })
}		
//获取最近10条会话列表
me.getChatList(10, 0);

//建立链接
 wx.connectSocket({
  url: api.create_ws,
  fail:function(){
    console.log("failfail");
  }
})
//监听 WebSocket 连接打开事件
wx.onSocketOpen(function (res) {
  that.setData({isSocket:1})
  wx.hideLoading();
  socketOpen = true;
  wx.showToast({
    title: '连接成功',
    icon: 'none',
    duration: 1500
  })
  console.log('WebSocket成功!')
  clearInterval(setIntervalMsg)
  sendSocketMessage(socketMsgQueue)
})

//每隔6秒发送心跳, 发送信息
function sendSocketMessage(msg) {
  setIntervalMsg = setInterval(function(){
    wx.sendSocketMessage({
      data:"{\"type\":\"type_heartbeat\"}",
      fail: function(){
        that.getChatList(10000, that.data.msg_id_last,"",function(){
           that.socket(that.data.model);
        })
      }
    })
  },6000);
  if (socketOpen) {
    wx.sendSocketMessage({
      data: msg
    })
  }
}

//接受服务端返回信息回调函数,实时更新room中信息
wx.onSocketMessage

Q: 如何模拟会话效果?
如果是本人,头像、昵称放在右边
如果不是本人,头像、昵称放在左边

Q: msg_offset 参数为负数是什么意思?什么时候这个值会是负值?

下拉刷新的时候,是负值。看之前的评论的意思。

onPullDownRefresh: function(){
    var me = this;
    if(me.data.tab==2){
      me.getChatList(-10, me.data.msg_id_current,"pull");
    }else{
      wx.stopPullDownRefresh();
      return;
    }
    wx.stopPullDownRefresh()
 },




msg_id_last: 最后消息id
msg_id_current:0,//基准消息 id


if (msg_offset < 0) {
  this.data.messages = response.data.msg_items.concat(this.data.messages);
} else {
  this.data.messages = this.data.messages.concat(response.data.msg_items);
}

12.3 播放逻辑

播放完此视频后,播放下一个视频,如何操作?
让当前播放对象pause,获取播放列表数组,index+1,如果不是最后一个视频,返回下一个视频course_id,向后台发送请求,获取视频详情。

使用 wx.createVideoContext 创建 vedio 对象,播放,如果不满足条件(没有购买,试看结束),弹卡提示

如何记录播放位置?
bindtimeupdate:function(e){ //获取播放进度
    var me = this;
    me.setData({currentTime:e.detail.currentTime});
},

//返回页面时,发送请求让后端记下,参数为 currentTime
onUnload: function () {
    this.sendHistory();
    this.socketClose();
},

12.4 点击视频列表逻辑

如果点击视频没有购买,返回
如果点击视频id 和当前视频一致,返回
否则,发送新请求,获取点击视频详情 		
当前播放视频回到初始位置,seek(0), 其他逻辑同播放下一个视频一致

12.5 如何跳到会话顶部?底部?

顶部逻辑,
wx.pageScrollTo({
    scrollTop: 0
}),

底部逻辑,创建查询对象,获取会话区域详情


wx.createSelectorQuery().select('#the-id').boundingClientRect(function(rect){
  rect.id      // 节点的ID
  rect.dataset // 节点的dataset
  rect.left    // 节点的左边界坐标
  rect.right   // 节点的右边界坐标
  rect.top     // 节点的上边界坐标
  rect.bottom  // 节点的下边界坐标
  rect.width   // 节点的宽度
  rect.height  // 节点的高度
}).exec()
},


wx.createSelectorQuery().select('#j_page')
.boundingClientRect(function(rect){
  wx.pageScrollTo({
    scrollTop: rect.bottom
  })
}).exec()	

13.curriculum 页面

13.1  最近学习   history_items  
13.2  购买的课程 order_items  
13.3 收藏的课程  collect_items

4. 问题汇总解答

  1. 怎么保存学习记录?

     bindtimeupdate, vedio组件的方法,播放进度变化时触发,
     event.detail = {currentTime, duration} 。
     触发频率 250ms 一次
     
     在页面看完的时候,提交上次学习记录
     onUnload: function () {
        this.sendHistory();
        this.socketClose();
     }
     
     第一个视频播放完毕后,标记 res.data.data.last_play_pos = 0;
     表示,再进入页面,第一个视频从头开始播放。
    
  2. 怎么获取上次学习记录?

     看完某个视频,会将该视频的观看信息返回后端,this.sendHistory
     第二次再load视频,后端返回开始时间数据
    
  3. 怎么创建订单?

     安卓手机可以通过点击,视频下方的立即购买按钮
    
  4. 怎么支付订单?

  5. 分享给第三人,点击如何跳转到分享的精确页面?

     通过login页面,scene参数判断,原分享页面来自哪里
    
  6. 购买的课程列表、收藏的课程列表

     通过点击 tab,向后端传递不同参数,后端返回
    
  7. 最近学习列表?

     默认向后端传currentNav=1, 默认学习列表page = 1, 后端返回
     当然也有onReachBottom处理函数,上拉获取更多视频数据
    
  8. 如何区分是课程一级列表,还是二级列表?

     点击8个icon, 到达的是课程分类页,其他的是课程播放页  
     跳到课程分类页:token + category_id + page_size  
     跳到课程播放页:token + course_id
    
  9. 跳转到课程详情页有哪些信息?

     课程标题、背景图、老师、购买状态、收藏状态、价格
     点赞数、是否已评论、是否能购买、iso用户???
     是否免费?播放次数、课程列表
     只有课程评论会重新发送请求。课程介绍和课程列表无。
    
  10. sso_token 和 token 有什么不同?

    电视账户sso_token ,用户 token
    
  11. 为什么不支持ios?

    暂停ios小程序虚拟支付
    
  12. 什么时候回同步视频信息?

    前提是有电视账号,值不为空
    
    第一种情况,有电视账号,
    if(that.data.sso_token && app.globalData.is_bind_sso==1 && that.data.isbind==0){}
    
    第二种情况,
    if(that.data.sso_token && that.data.isbind==0){}
    
  13. 绑定电视账号后,如何跳转到之前的页面?

    onLoad 的时候,记录e.from, 一般有两种情况,详情播放页,我的账号页
    
  14. 如何触底上拉,获取更多视频列表?

    onReachBottom 函数,页面上拉触底事件的处理函数
    触发这个函数,使得 this.data.pageIndex + 1
    重新向后端发送新的请求,返回page_size条数据
    然后把之前的数组 concat 后端返回的新数组,如[10] + [10]
    
  15. swiper组件的使用

  16. top箭头何时出现?出现了如何返回顶部?

    	onPageScroll	页面滚动触发事件的处理函数
    
      // 监听滚动条坐标,超过500出现滚动到顶部箭头
      onPageScroll: function (e) {
        //console.log(e)
        var me = this
        var scrollTop = e.scrollTop
        var backTopValue = scrollTop > 500 ? true : false
        me.setData({
          isUp: backTopValue
        })
      },
      
     //滚动到顶部函数
     wx.pageScrollTo({
      scrollTop: 0
    })
    
  17. 如何获取平台类型?

    wx.getSystemInfo({
      success (res) {
        app.globalData.platform = res.platform;
      }
    })
    
    
  18. 如何客服通话?

    //回话消息卡片,客户发送消息,可以在,微信-服务通知-客服小助手 中收到实时消息
    <button class="button"  open-type="contact" 
    session-from="weapp">意见反馈</button>
    
  19. 视频分类tab怎么做的?

    可滚动视图区域。scroll-view。
    哪几个参数?
    
    <scroll-view class="viewWrap categorys" scroll-x="true">
        <view class="layer_left"></view>
        <text class="text item_{{index}} {{category_id==item.category_id?'on':''}}" wx:for="{{categorys}}" data-id="{{item.category_id}}" bindtap="goList"  >{{item.name}}</text>
        <view class="layer_right"></view>
    </scroll-view>
    
    
  20. 如何使用canvas生成海报?

  21. 可操作区域高宽和屏幕高宽?

  22. 当前视频播放完毕如何自动播放下一个视频?

    如果直接替换video的src是不行的,通过wx.createVideoContext创建不同的video组件,通过不同的id区分,给当前视频绑定,bindend 函数
    
    结束时触发,停止当前视频播放
    获取下一个视频src
    
  23. onPullDownRefresh 和 onReachBottom 区别

    页面相关事件处理函数——监听用户下拉动作  
    页面上拉触发底事件的处理函数