• uniapp自定义播放器


    问题描述:我是真无语啊,就是有一个目录切换的地方,然后切换音频,结果你猜怎么着,嘿,音频他不播放了。也就是下面这个方法都不进去了打印的时候,音频播放都播放不了了,我尝试了销毁在播也不行。然后我寻思着,我写代码相同的我也喜欢return出去,会不会是这个原因,结果抱着试一试的态度,好家伙,真这样。

    解决方法:在后台设置的时候,换成两个不同的音频进行切换就完事了。一般测试阶段才会出现,我觉得正式用,人家也不会放两个相同的视频在一个课程里面把,并且呢,这个在h5是好的,小程序才会出现。

    代码:

    1. <template>
    2. <view class="wrap" v-if="!loadding">
    3. <view class="videoWrap">
    4. <view class="videoBox">
    5. <template v-if="!videoPause">
    6. <view class="masterPic">
    7. <image class="img" :src="detail.video_image" mode="scaleToFill"></image>
    8. </view>
    9. <image class="startIcon" src="/static/image/bofang.png" mode="scaleToFill" @click="startVideo"></image>
    10. </template>
    11. <template v-else>
    12. <video id="video" :src="detail.video_link" :autoplay="true" style="width: 100%;height: 100%"></video>
    13. </template>
    14. </view>
    15. <view class="contnet">
    16. <view class="title">{{ detail.title }}</view>
    17. <!-- <view class="num">视频已播放2596</view> -->
    18. <view class="num">{{ detail.update_time }}</view>
    19. </view>
    20. </view>
    21. <view class="auditorWrap" v-if="detail.audio_image">
    22. <image class="imgAuditor" :src="detail.audio_image" mode="scaleToFill"></image>
    23. <view class="contnet">
    24. <view class="title">{{ detail.title }}</view>
    25. <view class="num">{{ detail.update_time }}</view>
    26. </view>
    27. <view class="auditorBox">
    28. <view class="iconList">
    29. <image class="icon" src="/static/image/bofang1.png" mode="scaleToFill" v-if="!status" @click="changeto"></image>
    30. <image class="icon" src="/static/image/zanting.png" mode="scaleToFill" v-else @click="changeto"></image>
    31. </view>
    32. <view class="progressBox">
    33. <view class="progress">
    34. <view class="activeProgress" :style="{width:`${progress}%`}">
    35. <view class="activeRightBox">
    36. <view class="circle" v-show="progress > 0"></view>
    37. </view>
    38. </view>
    39. </view>
    40. <view class="timeBox">
    41. <view>{{ formatTime(currentTime) }}</view>
    42. <view>{{ formatTime(duration) }}</view>
    43. </view>
    44. </view>
    45. </view>
    46. </view>
    47. <view class="intro" v-if="detail.content">
    48. <view v-html="detail.content"></view>
    49. </view>
    50. <movable-area class="recordWrap">
    51. <movable-view :x="removeArea.x" :y="removeArea.y" direction="all" class="record">
    52. <view @click.stop="gotoRecourd">
    53. <image class="img" src="/static/image/recourdIcon.png" mode="scaleToFill"></image>
    54. <view class="label">课程目录</view>
    55. </view>
    56. </movable-view>
    57. </movable-area>
    58. <recourdVue :list="course.section" ref="recourdRef" />
    59. </view>
    60. </template>
    61. <script>
    62. import utils from '@/common/utils.js';
    63. import recourdVue from './part/recourd.vue';
    64. const innerAudioContext = uni.createInnerAudioContext();
    65. export default {
    66. components: {
    67. recourdVue
    68. },
    69. data() {
    70. return {
    71. /*商品id*/
    72. section_id: null,
    73. course_id: null,
    74. course: {},
    75. /*商品详情*/
    76. detail: {},
    77. status: false,
    78. beforeAudio: true,
    79. duration: 0,
    80. currentTime: 0,
    81. progress: 0,
    82. xpjAudio: null,
    83. videoPause: false,
    84. videoContext: null,
    85. removeArea:{
    86. x: 0,
    87. y: 0,
    88. }
    89. };
    90. },
    91. onReady() {
    92. console.log("onReady")
    93. this.videoContext = uni.createVideoContext('video', this);
    94. },
    95. onLoad(e) {
    96. console.log("onLoad")
    97. this.videoPause = false;
    98. /*商品id*/
    99. let scene = utils.getSceneData(e);
    100. this.section_id = e.section_id ? e.section_id : scene.sid;
    101. this.course_id = e.course_id ? e.course_id : scene.cid;
    102. this.getSystemInfo();
    103. },
    104. mounted() {
    105. console.log("mounted")
    106. /*获取产品详情*/
    107. this.getData();
    108. },
    109. methods: {
    110. getSystemInfo(){
    111. let self = this;
    112. uni.getSystemInfo({
    113. success(res) {
    114. self.removeArea.x = res.windowWidth - 70;
    115. self.removeArea.y = res.windowHeight - 120;
    116. }
    117. });
    118. },
    119. initAudit(){
    120. innerAudioContext.src = this.detail.audio_link;
    121. this.getAudioInfo();
    122. },
    123. getAudioInfo(){
    124. innerAudioContext.onCanplay(()=>{
    125. innerAudioContext.duration;
    126. setTimeout(() => {
    127. this.duration = innerAudioContext.duration;
    128. this.watchAuditTime();
    129. });
    130. })
    131. },
    132. watchAuditTime(){
    133. innerAudioContext.onTimeUpdate(() => {
    134. const { currentTime,duration} = innerAudioContext;
    135. this.currentTime = currentTime;
    136. if(this.duration == this.currentTime){
    137. this.progress = 100;
    138. this.status = false;
    139. }else{
    140. this.progress = currentTime/duration * 100;
    141. }
    142. });
    143. },
    144. gotoRecourd(){
    145. this.$refs.recourdRef.open(
    146. {
    147. section_id: this.section_id,
    148. course_id: this.course_id,
    149. }
    150. );
    151. },
    152. startVideo(){
    153. this.videoPause = true;
    154. this.$nextTick(()=>{
    155. this.videoContext.play();
    156. })
    157. },
    158. changeto(){
    159. this.status = !this.status;
    160. if (this.status) {
    161. innerAudioContext.play();
    162. innerAudioContext.onPlay(() => {
    163. // 播放监听
    164. console.log('播放!');
    165. });
    166. } else {
    167. innerAudioContext.pause()
    168. this.currenttime = innerAudioContext.currentTime
    169. }
    170. },
    171. /*获取数据*/
    172. getData() {
    173. let self = this;
    174. let section_id = self.section_id;
    175. let course_id = self.course_id;
    176. self.loadding = true;
    177. uni.showLoading({
    178. title: '加载中'
    179. });
    180. self._get(
    181. 'course.course/sectionDetail', {
    182. course_id: course_id,
    183. section_id: section_id,
    184. },
    185. function (res) {
    186. const { data: { detail: { course, detail } } } = res;
    187. self.course = course;
    188. self.detail = detail;
    189. self.initAudit();
    190. self.loadding = false;
    191. uni.hideLoading();
    192. },
    193. function (err) {
    194. }
    195. );
    196. },
    197. changeSwiper() {
    198. this.isVideoPlay = false;
    199. },
    200. formatTime(num) {
    201. num = Math.floor(num)
    202. let second = num % 60;
    203. if (second < 10) second = '0' + second;
    204. let min = Math.floor(num / 60);
    205. if (min < 10) min = '0' + min;
    206. return min + ":" + second;
    207. },
    208. }
    209. };
    210. </script>
    211. <style lang="scss" scoped>
    212. .videoWrap,.auditorWrap {
    213. background: #fff;
    214. .videoBox,.imgAuditor {
    215. width: 100%;
    216. height: 564rpx;
    217. position: relative;
    218. .masterPic {
    219. height: 100%;
    220. &::before {
    221. content: "";
    222. position: absolute;
    223. top: 0;
    224. left: 0;
    225. background: rgb(0, 0, 0, 0.45);
    226. width: 100%;
    227. height: 100%;
    228. z-index: 1;
    229. }
    230. .img {
    231. width: 100%;
    232. height: 100%;
    233. }
    234. }
    235. .startIcon {
    236. position: absolute;
    237. left: 50%;
    238. top: 50%;
    239. transform: translate(-50%, -50%);
    240. width: 92rpx;
    241. height: 92rpx;
    242. z-index: 10;
    243. }
    244. }
    245. .contnet{
    246. padding: 28rpx;
    247. .title{
    248. font-size: 32rpx;
    249. color: #333333;
    250. margin-bottom: 20rpx;
    251. }
    252. .num{
    253. font-size: 23rpx;
    254. color: #999999;
    255. }
    256. }
    257. }
    258. .auditorWrap{
    259. margin-top: 20rpx;
    260. }
    261. .auditorBox{
    262. display: flex;
    263. gap: 16rpx;
    264. padding: 28rpx;
    265. .iconList{
    266. width: 62rpx;
    267. height: 62rpx;
    268. .icon{
    269. width: 100%;
    270. height: 100%;
    271. }
    272. }
    273. .progressBox{
    274. flex: 1;
    275. }
    276. .progress{
    277. width: 100%;
    278. height: 20rpx;
    279. background: #EDE8E8;
    280. border-radius: 20rpx;
    281. position: relative;
    282. .activeProgress{
    283. position: absolute;
    284. left: 0;
    285. top: 0;
    286. background: #F2473F;
    287. height: 100%;
    288. border-radius: 20rpx;
    289. transition: width 1s ease;
    290. .activeRightBox{
    291. position: relative;
    292. height: 100%;
    293. .circle{
    294. width: 42rpx;
    295. height: 42rpx;
    296. background: #FFFFFF;
    297. border: 2rpx solid #F2473F;
    298. box-shadow: 0px 5rpx 5rpx 0px rgba(0,0,0,0.1);
    299. border-radius: 50%;
    300. position: absolute;
    301. right: 0;
    302. top: -12rpx;
    303. }
    304. }
    305. }
    306. }
    307. .timeBox{
    308. display: flex;
    309. justify-content: space-between;
    310. color: #F2473F;
    311. font-size: 32rpx;
    312. padding-top: 8rpx;
    313. }
    314. }
    315. .intro{
    316. margin-top: 20rpx;
    317. padding: 28rpx;
    318. background: #fff;
    319. }
    320. .recordWrap{
    321. position: fixed;
    322. bottom: 0;
    323. top: 0;
    324. width: 100vw;
    325. height: 100vh;
    326. pointer-events: none;
    327. }
    328. .record{
    329. width: 111rpx;
    330. height: 111rpx;
    331. background: linear-gradient(45deg, #F2473F, #F26E2F);
    332. border-radius: 50%;
    333. position: relative;
    334. pointer-events: visible;
    335. .img{
    336. width: 54rpx;
    337. height: 53rpx;
    338. position: absolute;
    339. top: 40%;
    340. left: 50%;
    341. transform: translate(-50%,-50%);
    342. }
    343. .label{
    344. width: 131rpx;
    345. height: 43rpx;
    346. line-height: 43rpx;
    347. background: linear-gradient(45deg, #F2473F, #F26E2F);
    348. box-shadow: 0px 5rpx 5rpx 0px rgba(9,2,4,0.25);
    349. font-size: 26rpx;
    350. color: #fff;
    351. text-align: center;
    352. position: absolute;
    353. bottom: -10rpx;
    354. left: -8rpx;
    355. border-radius: 20rpx;
    356. }
    357. }
    358. </style>

    recourd.vue 子组件

    1. <template>
    2. <view class="recourdMask" v-if="show">
    3. <view class="recourdBox">
    4. <view class="closeIcon" @click="closeIcon">
    5. <u-icon name="close" color="#424242" size="40rpx"></u-icon>
    6. </view>
    7. <view class="title">课程目录</view>
    8. <scroll-view :scroll-top="scrollTop" :scroll-y="true" class="content" scroll-with-animation="true">
    9. <view class="list">
    10. <view class="item" v-for="v in list" :key="v" @click="gotoLook(v)">
    11. <view class="txt">{{ v.title }}</view>
    12. <view class="status" v-if="v.is_see == 1">试学</view>
    13. </view>
    14. </view>
    15. </scroll-view>
    16. </view>
    17. </view>
    18. </template>
    19. <script>
    20. export default {
    21. props: {
    22. list: {
    23. type: Array,
    24. default: [],
    25. }
    26. },
    27. components: {},
    28. data() {
    29. return {
    30. params: {},
    31. show: false,
    32. }
    33. },
    34. methods: {
    35. open(params){
    36. this.params = params;
    37. this.show = true;
    38. },
    39. gotoLook(v){
    40. if(v.payStatus == 0 || v.is_see == 0){
    41. uni.showToast({
    42. icon: 'none',
    43. title: '此章节需要购买后查看'
    44. });
    45. return
    46. }
    47. this.params.section_id = v.section_id;
    48. this.gotoPage(`pages/knowledge/course/section-detail?section_id=${this.params.section_id}&course_id=${this.params.course_id}`,'redirect');
    49. },
    50. closeIcon(){
    51. this.show = false;
    52. }
    53. }
    54. }
    55. </script>
    56. <style lang="scss">
    57. .recourdMask{
    58. position: fixed;
    59. bottom: 0;
    60. background: rgba(0,0,0,0.45);
    61. top: 0;
    62. width: 100%;
    63. height: 100%;
    64. z-index: 10;
    65. .recourdBox{
    66. position: fixed;
    67. bottom: 0;
    68. height: 882rpx;
    69. background: #fff;
    70. width: 100%;
    71. border-top-left-radius: 20rpx;
    72. border-top-right-radius: 20rpx;
    73. z-index: 2;
    74. .list{
    75. padding: 20rpx;
    76. padding-top: 0;
    77. box-sizing: border-box;
    78. .item{
    79. display: flex;
    80. justify-content: space-between;
    81. align-items: center;
    82. background: #F5F6F8;
    83. padding: 26rpx 22rpx;
    84. box-sizing: border-box;
    85. border-radius: 20rpx;
    86. margin-bottom: 20rpx;
    87. }
    88. }
    89. .title{
    90. font-size: 32rpx;
    91. font-weight: bold;
    92. color: #333333;
    93. text-align: center;
    94. height: 124rpx;
    95. line-height: 124rpx;
    96. }
    97. .status{
    98. width: 112rpx;
    99. height: 48rpx;
    100. text-align: center;
    101. line-height: 48rpx;
    102. background: rgba(249,156,49,0.15);
    103. font-size: 22rpx;
    104. color: #F2473F;
    105. border-radius: 20rpx;
    106. }
    107. .txt{
    108. font-size: 26rpx;
    109. color: #666666;
    110. }
    111. }
    112. .content{
    113. height: 882rpx;
    114. }
    115. .closeIcon{
    116. position: absolute;
    117. right: 28rpx;
    118. top: 28rpx;
    119. }
    120. }
    121. </style>

    实现效果

    目前呢,这个播放器还没有做拖动的。这个得后续优化。

  • 相关阅读:
    第11/100天 阅读笔记
    Linux中如何禁止普通用户使用su命令
    ctf-pikachu-CSRF
    Java#28(集合进阶1---单列集合)
    网络安全入门学习资源汇总
    《OpenHarmony开源鸿蒙学习入门》-- 状态管理
    Linux Shell编程第5章——文件的排序、合并和分割
    MyBatis 中如何实现分页 ?
    自动创建设备节点udev机制实现
    自己更换尾插的视频教程
  • 原文地址:https://blog.csdn.net/weixin_45638909/article/details/133135170