Parcourir la source

修改播放逻辑

lex il y a 1 an
Parent
commit
d579377c1a

+ 90 - 6
src/views/coursewarePlay/component/video-play.tsx

@@ -9,10 +9,19 @@ import {
 import { ref } from 'vue';
 import styles from './video.module.less';
 
-import iconLoop from '../image/icon-loop.svg';
-import iconLoopActive from '../image/icon-loop-active.svg';
-import iconplay from '../image/icon-play.svg';
-import iconpause from '../image/icon-pause.svg';
+// import iconLoop from '../image/icon-loop.svg';
+// import iconLoopActive from '../image/icon-loop-active.svg';
+// import iconplay from '../image/icon-play.svg';
+// import iconpause from '../image/icon-pause.svg';
+
+import {
+  iconVideoBg,
+  iconLoop,
+  iconLoopActive,
+  iconPlay,
+  iconPause,
+  iconSpeed
+} from '../image/icons.json';
 
 import TCPlayer from 'tcplayer.js';
 import 'tcplayer.js/dist/tcplayer.min.css';
@@ -79,8 +88,14 @@ export default defineComponent({
       loop: false,
       playState: 'pause' as 'play' | 'pause',
       vudio: null as any,
-      showBar: true
+      showBar: true,
+      speedControl: false,
+      speedStyle: {
+        left: '1px'
+      },
+      defaultSpeed: 1 // 默认速度
     });
+    const speedBtnId = 'speed' + Date.now() + Math.floor(Math.random() * 100);
 
     const forms = reactive({
       subjectIds: [],
@@ -90,6 +105,7 @@ export default defineComponent({
     const videoItem = ref();
     const videoID = 'video' + Date.now() + Math.floor(Math.random() * 100);
     const toggleHideControl = (isShow: boolean) => {
+      data.speedControl = false;
       data.showBar = isShow;
     };
     // const togglePlay = (e: Event) => {
@@ -100,6 +116,7 @@ export default defineComponent({
     // 切换音频播放
     const onToggleAudio = (state: 'play' | 'pause') => {
       // console.log(state, 'state')
+      data.speedControl = false;
       clearTimeout(playTimer);
       if (state === 'play') {
         playTimer = setTimeout(() => {
@@ -114,6 +131,7 @@ export default defineComponent({
       emit('togglePlay', data.playState);
     };
     const toggleLoop = () => {
+      data.speedControl = false;
       if (!videoItem.value) return;
       if (data.loop) {
         videoItem.value.loop(false);
@@ -123,6 +141,7 @@ export default defineComponent({
       data.loop = !data.loop;
     };
     const changePlayBtn = (code: string) => {
+      // data.speedControl = false;
       if (code == 'play') {
         data.playState = 'play';
       } else {
@@ -272,6 +291,11 @@ export default defineComponent({
         autoplay: true
       }); // player-container-id 为播放器容器 ID,必须与 html 中一致
       __initVideo();
+
+      document.getElementById(speedBtnId)?.addEventListener('click', e => {
+        e.stopPropagation();
+        data.speedControl = !data.speedControl;
+      });
     });
 
     watch(
@@ -358,15 +382,75 @@ export default defineComponent({
                   e.stopPropagation();
                   onToggleAudio(data.playState === 'pause' ? 'play' : 'pause');
                 }}>
-                <img src={data.playState === 'pause' ? iconplay : iconpause} />
+                <img src={data.playState === 'pause' ? iconPlay : iconPause} />
               </div>
               <div class={styles.actionBtn} onClick={toggleLoop}>
                 <img src={data.loop ? iconLoopActive : iconLoop} />
               </div>
+              <div class={styles.actionBtn} id={speedBtnId}>
+                <img src={iconSpeed} />
+              </div>
             </div>
             <div class={styles.name}>{item.value.name}</div>
           </div>
         </div>
+
+        <div
+          style={{
+            display: data.speedControl ? 'block' : 'none'
+          }}>
+          <div
+            class={styles.sliderPopup}
+            onClick={(e: Event) => {
+              e.stopPropagation();
+            }}>
+            <i
+              class={styles.iconAdd}
+              onClick={() => {
+                if (data.defaultSpeed >= 1.5) {
+                  return;
+                }
+
+                if (videoItem.value) {
+                  data.defaultSpeed = (data.defaultSpeed * 10 + 1) / 10;
+                  videoItem.value.playbackRate(data.defaultSpeed);
+                }
+              }}></i>
+            <Slider
+              min={0.5}
+              max={1.5}
+              step={0.1}
+              v-model={data.defaultSpeed}
+              vertical
+              barHeight={5}
+              reverse
+              onChange={() => {
+                if (videoItem.value) {
+                  videoItem.value.playbackRate(data.defaultSpeed);
+                }
+              }}>
+              {{
+                button: () => (
+                  <div class={styles.sliderPoint}>
+                    {data.defaultSpeed}
+                    <span>x</span>
+                  </div>
+                )
+              }}
+            </Slider>
+            <i
+              class={[styles.iconCut]}
+              onClick={() => {
+                if (data.defaultSpeed <= 0.5) {
+                  return;
+                }
+                if (videoItem.value) {
+                  data.defaultSpeed = (data.defaultSpeed * 10 - 1) / 10;
+                  videoItem.value.playbackRate(data.defaultSpeed);
+                }
+              }}></i>
+          </div>
+        </div>
       </div>
     );
   }

+ 331 - 102
src/views/coursewarePlay/component/video.module.less

@@ -1,133 +1,362 @@
+// .videoWrap {
+//     width: 100%;
+//     height: 100%;
+
+//     :global {
+//         .plyr--video {
+//             width: 100%;
+//             height: 100%;
+//         }
+
+//         .plyr__time {
+//             display: block !important;
+//         }
+//         .plyr__video-wrapper{
+//             pointer-events: none;
+//         }
+//     }
+// }
+
+// :global(.bottomFixed).controls {
+//     width: 100%;
+//     background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
+//     padding: 0 !important;
+//     flex-direction: column;
+//     transition: all 0.5s;
+
+//     .time {
+//         display: flex;
+//         justify-content: space-between;
+//         width: 100%;
+//         color: #fff;
+//         font-size: 10px;
+//         padding: 4px 20px;
+
+//         :global {
+//             .plyr__time+.plyr__time:before {
+//                 content: '';
+//             }
+//         }
+//     }
+
+//     .slider {
+//         width: 100%;
+//         padding: 0 20px;
+
+//         :global {
+//             .van-slider__button {
+//                 background: var(--van-primary);
+//             }
+
+//             .van-loading {
+//                 width: 100%;
+//                 height: 100%;
+//             }
+//         }
+//     }
+
+//     .actions {
+//         display: flex;
+//         justify-content: space-between;
+//         width: 100%;
+//         color: #fff;
+//         font-size: 12px;
+//         padding: 0 20px;
+//         align-items: center;
+
+//         .actionWrap {
+//             display: flex;
+//         }
+
+//         .actionBtn {
+//             display: flex;
+//             width: 38px;
+//             height: 38px;
+//             padding: 4px 0;
+//             background: transparent;
+//         }
+
+//         .actionBtn>img {
+//             width: 100%;
+//             height: 100%;
+//         }
+
+//         :global {
+//             .van-loading__circular {
+//                 width: 100%;
+//                 height: 100%;
+//             }
+//         }
+
+//         .playIcon {
+//             display: none;
+//         }
+
+//         .btnPlay img:nth-child(2) {
+//             display: block;
+//         }
+
+//         .btnPause img:nth-child(3) {
+//             display: block;
+//         }
+
+//         .btnPlay,
+//         .btnPause {
+//             :global {
+//                 .van-loading {
+//                     display: none;
+//                 }
+//             }
+//         }
+//         .loopBtn{
+//             :global{
+//                 .loop{
+//                     display: block;
+//                 }
+//                 .loopActive{
+//                     display: none;
+//                 }
+//             }
+//         }
+//         .loopBtn.active{
+//             :global{
+//                 .loop{
+//                     display: none;
+//                 }
+//                 .loopActive{
+//                     display: block;
+//                 }
+//             }
+//         }
+
+//     }
+// }
+
 .videoWrap {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .videoSection {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 8;
+  }
+}
+
+.content {
+  position: relative;
+  height: 100%;
+}
+
+.contentWrap {
+  height: 100%;
+
+  video {
     width: 100%;
     height: 100%;
+  }
+}
+
+.controls {
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  height: 80px;
+  background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  transition: all 0.5s;
+  width: 100%;
+  z-index: 9;
+
+  &.hide {
+    transform: translateY(100%);
+  }
+
+  .time {
+    display: flex;
+    justify-content: space-between;
+    // width: 100%;
+    color: #fff;
+    font-size: 10px;
+    padding: 4px 20px;
+  }
+
+  .slider {
+    // width: 100%;
+    padding: 0 20px;
+    --van-slider-button-width: 13px !important;
+    --van-slider-button-height: 13px !important;
 
     :global {
-        .plyr--video {
-            width: 100%;
-            height: 100%;
-        }
+      .n-slider {
+        --n-handle-size: 13px !important;
+        --n-fill-color: var(--van-primary-color) !important;
+        --n-fill-color-hover: var(--van-primary-color) !important;
+      }
 
-        .plyr__time {
-            display: block !important;
-        }
-        .plyr__video-wrapper{
-            pointer-events: none;
-        }
+      .van-loading {
+        width: 100%;
+        height: 100%;
+      }
     }
-}
+  }
 
-:global(.bottomFixed).controls {
-    width: 100%;
-    background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
-    padding: 0 !important;
-    flex-direction: column;
-    transition: all 0.5s;
-
-    .time {
-        display: flex;
-        justify-content: space-between;
-        width: 100%;
-        color: #fff;
-        font-size: 10px;
-        padding: 4px 20px;
-
-        :global {
-            .plyr__time+.plyr__time:before {
-                content: '';
-            }
-        }
+  .actionSection {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 0 16px 8px 15px;
+
+    .name {
+      font-size: 14px;
+      font-weight: 500;
+      color: #FFFFFF;
     }
+  }
 
-    .slider {
-        width: 100%;
-        padding: 0 20px;
+  .actions {
+    display: flex;
+    // width: 100%;
+    color: #fff;
+    font-size: 12px;
 
-        :global {
-            .van-slider__button {
-                background: var(--van-primary);
-            }
+    align-items: center;
 
-            .van-loading {
-                width: 100%;
-                height: 100%;
-            }
-        }
+    .actionWrap {
+      display: flex;
+    }
+
+    .actionBtn {
+      display: flex;
+      width: 30px;
+      height: 30px;
+      padding: 4px 0;
+      background: transparent;
+
+      &+.actionBtn {
+        // margin-left: 12px;
+      }
     }
 
-    .actions {
-        display: flex;
-        justify-content: space-between;
+    .actionBtn>img {
+      width: 100%;
+      height: 100%;
+    }
+
+    :global {
+      .van-loading__circular {
         width: 100%;
-        color: #fff;
-        font-size: 12px;
-        padding: 0 20px;
-        align-items: center;
+        height: 100%;
+      }
+    }
 
-        .actionWrap {
-            display: flex;
-        }
+    .playIcon {
+      display: none;
+    }
 
-        .actionBtn {
-            display: flex;
-            width: 38px;
-            height: 38px;
-            padding: 4px 0;
-            background: transparent;
-        }
+    .btnPlay img:nth-child(2) {
+      display: block;
+    }
 
-        .actionBtn>img {
-            width: 100%;
-            height: 100%;
-        }
+    .btnPause img:nth-child(3) {
+      display: block;
+    }
 
-        :global {
-            .van-loading__circular {
-                width: 100%;
-                height: 100%;
-            }
+    .btnPlay,
+    .btnPause {
+      :global {
+        .van-loading {
+          display: none;
         }
+      }
+    }
 
-        .playIcon {
-            display: none;
+    .loopBtn {
+      :global {
+        .loop {
+          display: block;
         }
 
-        .btnPlay img:nth-child(2) {
-            display: block;
+        .loopActive {
+          display: none;
         }
+      }
+    }
 
-        .btnPause img:nth-child(3) {
-            display: block;
+    .loopBtn.active {
+      :global {
+        .loop {
+          display: none;
         }
 
-        .btnPlay,
-        .btnPause {
-            :global {
-                .van-loading {
-                    display: none;
-                }
-            }
-        }
-        .loopBtn{
-            :global{
-                .loop{
-                    display: block;
-                }
-                .loopActive{
-                    display: none;
-                }
-            }
-        }
-        .loopBtn.active{
-            :global{
-                .loop{
-                    display: none;
-                }
-                .loopActive{
-                    display: block;
-                }
-            }
+        .loopActive {
+          display: block;
         }
+      }
+    }
+
+  }
+}
+
+.sliderPopup {
+  position: absolute;
+  z-index: 9999;
+  left: 74px;
+  bottom: 46px;
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  height: 165px;
+  width: 45px;
+  padding: 10px 0 15px;
+  background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAGaCAMAAAC46aQwAAAAOVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC8dlA9AAAAE3RSTlNaAAxUVwdPRSc7MzYsEEoXGgshjXaABwAAAZBJREFUeNrt1GtO40AQReF77X46tvPY/2IHhiCDA0Ez7pb4cb4FHLVaVSU/isM/i360S5+nnIL+Q0h5On+fXuqoQ8a6fJm+VjVQr4/pEtREKPt0VTP1UzpmNZTjh3RWU3lLn9TY6T1d1Fx5S8eg5kL8m57UwfSaHoI6CIPlSV1MlpO6SNaiThbN6mRWVSdVWZ1kJXWSFNRJEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg9wnqJGhVJ6uyOsmq6qSqqJOiqzq5yqu6WC3P6mK2HEd1MEbLfZ49+zXtpOaS39IXNXe5p13UWPF72ic1dfKW9ql1eUu7tP2NLf3inNREOnuXflFGHTaWrSdvYsk6JJfoXXoTb1PNabwL+kEY71Ku023r7tOPYv5pFJ6Rn5qfj8KRtC+jvjGefSztYdWX1sFH0k82tUY3SPsWtDfZTdJekj4JN7dKO1Z9kBY3ST+er3x10/R2vqrdOO04BUnp4nbpTVwug30g3cwf1jMLKix6VfsAAAAASUVORK5CYII=') no-repeat top center;
+  background-size: contain;
+
+  .iconAdd,
+  .iconCut {
+    display: inline-block;
+    width: 24px;
+    height: 24px;
+    background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAABGlBMVEUAAAAAraMAraEArKEArqIA18kArqIA08UA1McAq6AAraAArKAArKEArKAArKAAq6EA1MYAq6AArKIAraMA2csAr6AA28kAn58A1skA0sQA1ccA2csA1cgArZ8A3M4Ar6IA1cgA2csA3M0A1MUA3M0A39EA2swA1skA1cgA3tAA3c8A3c0A08cA2swAq58A3M4A2csA4NL ///8A3tAA1sgA2s0A3M4A18kA4tQA2MsA3c8A2cwA1McArKAA08UA5NVm6+Jm6N9x599m6eEAx7oAvLDr/PsA0MNM49oAua2j8u2H8OmH7OZM6N4As6dt5t413dII1skD1skAy74AwLRf49ta49sn2s4X2MwT18tW4tpJ4Nc33tMq288faTE+AAAAMXRSTlMAGfxfUkc/9YXw6M/FtrCSUEM0MiMjCgj4z7quqG3x7tfPg1hS+Pjr69C6lZWKbVhYjYIARgAAAqJJREFUSMelk2lD2kAQhjfhkltQ0Xpbe98xJljCRo6EgApKoa32+P9/o7NOliEboB98Pj/v7MzsLotRS63tHb/Z2Xl9vLeWqrH/kdrPuE3B+SM7+6mV+voz15336/X615MXS/XNXTfuA7ubi/3TjOpjwHEOvyzy19yF9cF3LOt53P+w3IeA9X5R/fHfe9SpHyf0Y2ecgv/zttO5kwGwZT+I/Tmynwz4HeA3lY/4tm0fzu8K9vlwC/6vcRi46fVuIj7wjvx1mPY7+P1vYf3+GdB3APIbDbpBuN878H9Iv94WgTbVBx14K/0UHnD7gD4FpI8B05Tvah/W3+50/tC8GIjUB9/cQ7+Wge3fYUPoy4Dimy9rOHJTcD+m68VAN/Qb6AvW8ZLV50ABe9Y/8hF3FH+eMkA+csIEGXo+/TZyJQJXXaDVag2lbxivhK8FM//mbCHX0jcaGgTS1E9vcaCHPmCmIZBsztpfETCQJAQS7mzcpS1J30yIQEDrEUN3ARy6hQxnB1xYIpD0RIB+o6ArAq1wneRfBEkx9LSu+laLAqiHAU8MrQ1U37bxBBOROuBrDDg6V36vbeMJMd84YoKSp/gyoPqXQYkJDgbgR38jBciHgP+JCTQ9oPbnA4p+6egae6Q4oADYwFAEhuhTwC8ypMInlvIdr3u9a9MIE6hfNnmFhRRGdeo/el3kG6MCk1R1n3zlutAHpnqVzShzD9uhAyI64PEyI7bz3BP+8voTnt9mc2zlRAJ1df1YP7fFImxkuW8tK29MeXaDKWzk+ChQXrPc54jnyKeu8pz75+gjqDs+53nsR2G7rHM+mER8IwBdL+O8caoFDgy8wGnA/7Vcz+dAocqWUynqPIJerLDVaAelrLSzpQNtlUuhdDKRSKZRfir/ACF6Xp1EeZtPAAAAAElFTkSuQmCC') no-repeat center;
+    background-size: contain;
+    flex-shrink: 0;
+
+    &.disabled {
+      opacity: 0.7;
+    }
+  }
+
+  .iconCut {
+    background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAABCFBMVEUAAAAAraMAraEArKEArKEArqIArqIA2swA1cgA1sgAraAArKAArKEArKAArKAAq6EA2MoArZ8Aq6AArKIAraMAr6AA28kAn58A18oA08cA1cgA1MYA1sgA0cQA3c4A1skA08YA2swA08UA1skA2MsA2s0A18kA1sgA39AAzsIA3tAA2swA39EA39AA39EA4tMA3tAA2s0A2MoA1skA3M4A1ccA49QA3c8A2cwA4NIA4dP ///8ArKAA08Zx599x5t8A5NXi+/kA0cMAyLsAvK8Aua1J4dg13dIAzsAAvrIAs6dt5t4s29AD1chJ595h49tX49oV18sO1soAxLdm5NxS4tgd2MwAwrWCpB5XAAAAMHRSTlMAGfzvX1I/V1FH6M/FtrCShm1DNDIjCgj486iEI/jx19DPurGV+Ovr0M26uqiHSCOYWU5AAAACYklEQVRIx6WT12LaMBSGZTMS9p4hSTO6FwGMRyXj2GbTNqPj/d+kOjYCGcnkot/19/8+R5KRQDNzdnP5tt1+c3lTzjTRS2S6HaIFDCmDdjdzVD99RQjzgwDl6jRW710T0R8Yxsee3D/pMJ/C+cbdxYnMPyNPmz9CP/iUsujfks16Ys8FnwaAW7F/M5nY9kycJ2A0Kh/MTx7XNPD7u7x/RIns0euQn9SfSXwW0C++coFrMqf+gxbXDwH9A3dfhH7AXj/F9oOv9/dD0fv9ZYcnFOOPqN9/x/wMIWRuPxzth0D/CwrpwgU/Cgvv60EHPoV+83z/gMR92TyA2WQrM53CfBaA+l0gfLhlPjAI4OfnfPMzAt7LHmjIgW9eIeA8zh8d+tZr8BWXm2d2/03g/gfzLV2hgTTh5gdfTDDfMtM0kCLUfylgbgMpGkiSXX/cSMwf95MQWAgXLJwP+BC4g0DKY7rwIJjf3/pjNwVL/wVf7OcCzB97sLQylflM53yKryBKQhse8U3OtxIIKHoSX5gHcIsIqEyPz2Myf+xXEKCoLvUpsf3jEENVUEBhGnnQOiDpd5YFFFLFC+GHD2HzB2i4irbkV0PphYHPAo61yiNGTfWjvtjvOEu1hnaU8HNkX3Fhx8MltKeVw57Yb3L9C5xrIY5GFj/LL5j1ZxsoQj2BfUM8zxBriRN1dEA9i1eu9MIcbYWzzOenymHsa+KBGkuMcw0koVVSMZ4udP4DlutjrJZaSE4tjylTzx2M6G9muJ6PKfkaiqdaUHEEtVBFx1EqxQSzE8WKIgjSUDqVTKbSIP8//wBbnlQnTJqlUQAAAABJRU5ErkJggg==') no-repeat center;
+    background-size: contain;
+  }
+
+  .sliderPoint {
+    background: #FFFFFF;
+    box-shadow: 0px 2px 4px 0px rgba(102, 102, 102, 0.77);
+    border-radius: 10px;
+    font-size: 14px;
+    font-weight: 500;
+    color: rgba(1, 193, 181, 1);
+    min-width: 35px;
+    text-align: center;
+    vertical-align: text-bottom;
+
+    span {
+      font-size: 12px;
+    }
+  }
 
+  :global {
+    .van-slider {
+      margin: 7px 0;
     }
+  }
 }

+ 0 - 1
src/views/coursewarePlay/index.tsx

@@ -715,7 +715,6 @@ export default defineComponent({
                 ref={(el: any) => (data.videoItemRef = el)}
                 item={activeVideoItem.value}
                 activeModel={activeData.model}
-                // isEmtry={isEmtry}
                 onPlay={() => {
                   data.videoState = 'play';
                   data.animationState = 'end';