某在线视频播放小程序项目总结
1.项目简介
一款为家庭用户设计的实用技能学习平台,在tv端和小程序端都可以通过平台选择感兴趣的视频进行学习,小程序端主要功能包括3个tabBar:
- 视频分类展示
- 我的课程:最近学习课程、已有课程、收藏课程
- 个人账号管理:同步电视学习、意见反馈等
2. 主要工作和疑难点汇总
2.1 主要工作
- 封装api请求,改造wx.requeset方法,封装http请求
- 抽取公共样式文件,在每个page文件夹的.wxss文件中,通过import 引入,
如:@import "../../lib/base.wxss"; - 抽取公共组件,如底部分享组件、弹框组件,通过在各个页面配置usingComponents参数使用。
- 封装全局公共函数
- 业务逻辑
2.2 疑难点汇总
- 怎么保存学习记录?
- 怎么获取上次学习记录?
- 怎么创建订单?
- 怎么支付订单?
- 分享给第三人,点击如何跳转到分享的精确页面?
- 购买的课程列表、收藏的课程列表,从哪里拿到?
- 最近学习列表?这个是怎么拿到的?
- 如何区分是课程一级列表,还是二级列表?
- 跳转到课程详情页有哪些信息?
- sso_token 和 token 有什么不同?
- 为什么不支持ios下购买?
- 什么时候会同步电视端课程?
- 绑定电视账号后,如何跳转到之前的页面?
- 如何第一次只返回第一页,下拉分页,获取更多视频列表?
- swiper组件的使用
- top箭头何时出现?出现了如何返回顶部?
- 如何获取平台类型?
- 如何客服通话?
- 视频分类tab怎么做的?
- 如何使用canvas生成海报?
- 可操作区域高宽和屏幕高宽?
- 当前视频播放完毕如何自动播放下一个视频?
- 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.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. 问题汇总解答
-
怎么保存学习记录?
bindtimeupdate, vedio组件的方法,播放进度变化时触发, event.detail = {currentTime, duration} 。 触发频率 250ms 一次 在页面看完的时候,提交上次学习记录 onUnload: function () { this.sendHistory(); this.socketClose(); } 第一个视频播放完毕后,标记 res.data.data.last_play_pos = 0; 表示,再进入页面,第一个视频从头开始播放。
-
怎么获取上次学习记录?
看完某个视频,会将该视频的观看信息返回后端,this.sendHistory 第二次再load视频,后端返回开始时间数据
-
怎么创建订单?
安卓手机可以通过点击,视频下方的立即购买按钮
- 怎么支付订单?
-
分享给第三人,点击如何跳转到分享的精确页面?
通过login页面,scene参数判断,原分享页面来自哪里
-
购买的课程列表、收藏的课程列表
通过点击 tab,向后端传递不同参数,后端返回
-
最近学习列表?
默认向后端传currentNav=1, 默认学习列表page = 1, 后端返回 当然也有onReachBottom处理函数,上拉获取更多视频数据
-
如何区分是课程一级列表,还是二级列表?
点击8个icon, 到达的是课程分类页,其他的是课程播放页 跳到课程分类页:token + category_id + page_size 跳到课程播放页:token + course_id
-
跳转到课程详情页有哪些信息?
课程标题、背景图、老师、购买状态、收藏状态、价格 点赞数、是否已评论、是否能购买、iso用户??? 是否免费?播放次数、课程列表 只有课程评论会重新发送请求。课程介绍和课程列表无。
-
sso_token 和 token 有什么不同?
电视账户sso_token ,用户 token
-
为什么不支持ios?
暂停ios小程序虚拟支付
-
什么时候回同步视频信息?
前提是有电视账号,值不为空 第一种情况,有电视账号, if(that.data.sso_token && app.globalData.is_bind_sso==1 && that.data.isbind==0){} 第二种情况, if(that.data.sso_token && that.data.isbind==0){}
-
绑定电视账号后,如何跳转到之前的页面?
onLoad 的时候,记录e.from, 一般有两种情况,详情播放页,我的账号页
-
如何触底上拉,获取更多视频列表?
onReachBottom 函数,页面上拉触底事件的处理函数 触发这个函数,使得 this.data.pageIndex + 1 重新向后端发送新的请求,返回page_size条数据 然后把之前的数组 concat 后端返回的新数组,如[10] + [10]
- swiper组件的使用
-
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 })
-
如何获取平台类型?
wx.getSystemInfo({ success (res) { app.globalData.platform = res.platform; } })
-
如何客服通话?
//回话消息卡片,客户发送消息,可以在,微信-服务通知-客服小助手 中收到实时消息 <button class="button" open-type="contact" session-from="weapp">意见反馈</button>
-
视频分类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>
- 如何使用canvas生成海报?
- 可操作区域高宽和屏幕高宽?
-
当前视频播放完毕如何自动播放下一个视频?
如果直接替换video的src是不行的,通过wx.createVideoContext创建不同的video组件,通过不同的id区分,给当前视频绑定,bindend 函数 结束时触发,停止当前视频播放 获取下一个视频src
- onPullDownRefresh 和 onReachBottom 区别
页面相关事件处理函数——监听用户下拉动作
页面上拉触发底事件的处理函数
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。