目录
页面层级结构的加载和回退
filePath编码
对象的深度克隆
弹幕的加载
编辑
uni-app内置浏览器加载视频失败
后台报错 java.io.IOException: 你的主机中的软件中止了一个已建立的连接
安卓里遍历uni-list-item错误
手机自带浏览器无法加载视频
乱码问题
video中initial-time失效
手动设置视频初始时间
video的@progress失效
视频播放结束后,不能直接设置历史记录为结束时间
mybatis中关联查询
代码
前几周一直在用uni-app练手,于是乎写了一个视频播放器,从一开始粗糙版,到加入了数据库后的简易版。
其中记录一下坑。
代码的话已经提交到github,可能后续还会维护下去,看自己有什么好的想法吧。
页面层级结构的加载和回退
如图所示,在在加载数据后,进入第二层,第三层目录后,如何回退到父级目录。
这里就考虑一个数据接口,栈,先进后出。
页面中定义一个parentDir: [],
filePath编码
如果是运行在安卓手机中当app,则window.encodeURI是无效的,所以需要使用
this.nowFilePath = encodeURIComponent(this.nowFilePath);
对象的深度克隆
将一个object对象push到栈中时,加入的仅仅是这个对象的引用,改变了对象引用,栈里面的指向也会改变,所以需要深度克隆。
弹幕的加载
在页面上可以看到danmuList是一个数组,从后台请求这个视频的弹幕信息,而如果没有这个v-if的话,弹幕是不会展示的。
因为页面video组件已经加载完成,此时即使加载了弹幕数据,也压根无用。
所以才需要在获取数据后展示video组件,如此加载弹幕。
uni-app内置浏览器加载视频失败
官网有说明,所以如果是调试,可以运行到chrome等浏览器
后台报错 java.io.IOException: 你的主机中的软件中止了一个已建立的连接
此问题尚未真正解决
这种有两种情况,第一种是视频的编码不符合video的编码格式。
HTML <video> 标签 | 菜鸟教程
所以如果不符合上述三种格式的,就需要使用代码转变格式。
com.lw.familysystem.video.VideoUtils#encode
第二中情况是视频流的跨域问题,
com.lw.familysystem.video.VideoService#playVideo
直接在此方法中加入允许跨域请求,
response.addHeader("Access-Contro1-A11ow-0rigin","*");
后记:其实还是会经常出现这个问题,但是不影响播放。
安卓里遍历uni-list-item错误
<uni-list-item v-for="(item,index) in directories.childDirList" :key="item.filePath" :title="item.name"
note="目录"
thumb="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png"
thumb-size="lg" rightText="点击进入" clickable link @click="toNext(item,index)"></uni-list-item>
在chrome中上述代码没问题,但是运行到手机中,就会出现,
TypeError: Invalid attempt to destructure non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method. at view.umd.min.js:1
手机自带浏览器无法加载视频
这个问题暂时还没解决,换了手机里的chrome浏览器后,访问地址能加载视频。
乱码问题
路径变成了ascii码,统一编码。
其实最好路径不要用中文,就不会有乱码。
上述使用的是tag V0.0.2中代码遇到的坑。
video中initial-time失效
猜测应该是只有当video第一次初始化,然后加载视频时有用,而我获取视频是在onLoad中加载视频,而video组件出现是在onShow中。
onLoad中请求后台视频数据时,video可能已经在页面加载,而此时还没有设置url,导致视频会出现加载失败,此时initial-time自然无效。
当onLoad中请求了视频数据后,给video设置了url后,虽然能播放后台数据,但此时initial-time已经没有效果了。
经验证,上述猜测错误,真正原因是在playVideo方法中,将response的返回状态码设置为200,而不是206。
返回206是客户端表明自己只需要目标URL上的部分资源的时候返回的,比如video组件只需要先知道视频的长度,而不需要全部加载视频。
而200则让完全加载视频信息等。
//返回码需要为206,而不是200
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
手动设置视频初始时间
不可能每次都调整initial-time,所以需要手动设置,就需要使用到uni.createVideoContext创建的对象了。
所以就需要用到 videoContext.seek()方法了,
getVideoHistoryM() {
var param = {
loginName: this.loginName,
videoId: this.videos[this.nowPlayIndex].videoId
}
getVideoHistory(param).then(res => {
if (res?.result_code == "0") {
if (res.data) {
var history = res.data;
this.startTime = history.playTime;
this.videoContext.seek(this.startTime); //跳转到指定秒
}
}
});
},
video的@progress失效
当视频播放完后,一轮循环已经结束,再自动从头开始播放第一集的时候,此时并不会再进入@progress中的方法,所以就需要在@loadedmetadata 中的方法里判断下。
loadedMetaData(e) {//视频加载完毕
const {
duration
} = e.detail
// 记录视频总时间
this.duration = duration
if(!this.autoPlaying){
if(!this.firstVideo){//非第一个视频,自动播放
this.play();
}
}
this.videoContext.playbackRate(1.5);
},
onProgressVideo(e){
const {buffered} = e.detail;
console.log(buffered)
if(buffered>4){//视频加载了百分之 就自动播放
if(!this.firstVideo){//非第一个视频,自动播放
this.play();
}
}
},
视频播放结束后,不能直接设置历史记录为结束时间
比如,有个视频,时长18秒,再timeUpdate方法中监测到播放结束时,需要保存历史记录,那么此时不能保存为18秒,否则,下一刻再次点击这个视频时,就自动定位到18秒,然后跳转到下一个视频了,就永远也看不了这个视频了。
//播放结束后保存历史记录
this.currentPlayTime = 0;
this.savePlayHistoryM()
所以直接将当前时间重置,那么下次就是重头开始播放了。
mybatis中关联查询
left join 了多个表,需要将连接表的内容放入组合的vo中。如下所示,返回的Vo中内联了两个vo。
@Data
public class VideoPlayHistoryVo extends VideoPlayHistory {
private String createTimeFmt;
private String updateTimeFmt;
private VideoPhysicsInfoVo videoPhysicsInfoVo;
private VideoInfoVo videoInfoVo;
}
在xml中也需要编写内联的,association的property值要和VideoPlayHistoryVo中的内联名字相同。
<resultMap id="videoHistoryVoResultMap" type="com.lw.familysystem.vo.VideoPlayHistoryVo">
<id property="historyId" column="history_id"/>
<result property="videoId" column="video_id"/>
<result property="accountName" column="account_name"/>
<result property="playTime" column="play_time"/>
<result property="playTimeVis" column="play_time_vis"/>
<result property="createTimeFmt" column="create_time_fmt"/>
<result property="updateTimeFmt" column="update_time_fmt"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<association property="videoPhysicsInfoVo" javaType="VideoPhysicsInfoVo">
<id property="videoId" column="video_id"/>
<result property="videoName" column="video_name"/>
<result property="infoId" column="info_id"/>
<result property="orderNo" column="order_no"/>
<result property="quarterInfo" column="quarter_info"/>
<result property="relativePath" column="relative_path"/>
<result property="createTimeFmt" column="create_time_fmt"/>
<result property="updateTimeFmt" column="update_time_fmt"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</association>
<association property="videoInfoVo" javaType="VideoInfoVo">
<id property="infoId" column="info_id"/>
<result property="videoName" column="info_name"/>
<result property="videoType" column="video_type"/>
<result property="orderNo" column="order_no"/>
<result property="categoryId" column="category_id"/>
<result property="relativePath" column="relative_path"/>
<result property="createTimeFmt" column="create_time_fmt"/>
<result property="updateTimeFmt" column="update_time_fmt"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</association>
</resultMap>
在页面上就如下这样使用,例子可以看mine.vue
<uni-list-item v-for="(history,index) in histories" :key="index" :title="history.videoPhysicsInfoVo.videoName"
:note="history.videoInfoVo.videoName"
:rightText="''+history.playTimeVis" clickable link
@click="toPlayVideoPage(history.videoPhysicsInfoVo.infoId,history.videoPhysicsInfoVo.videoId)">
</uni-list-item>
上述问题是 tag V0.0.3遇到的问题
代码
后端
前端