index.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import {
  2. PropType,
  3. Transition,
  4. computed,
  5. defineComponent,
  6. reactive,
  7. ref,
  8. watch
  9. } from 'vue';
  10. import styles from './index.module.less';
  11. import { NButton, NImage, NProgress, NSlider } from 'naive-ui';
  12. import { IMusicItem } from '../../type';
  13. import icon_pre from '../../images/icon_pre.svg';
  14. import icon_next from '../../images/icon_next.svg';
  15. import icon_play from '../../images/icon_play.svg';
  16. import icon_pause from '../../images/icon_pause.svg';
  17. import { getSecondRPM } from '/src/utils';
  18. import icon_favitor from '/src/common/images/icon-collect-default.png';
  19. import icon_favitorActive from '/src/common/images/icon-collect-active.png';
  20. import TheNoticeBar from '/src/components/TheNoticeBar';
  21. export default defineComponent({
  22. name: 'playItem',
  23. props: {
  24. item: {
  25. type: Object as PropType<IMusicItem>,
  26. default: () => ({})
  27. },
  28. show: {
  29. type: Boolean,
  30. default: false
  31. },
  32. playState: {
  33. type: String as PropType<'play' | 'pause'>,
  34. default: 'pause'
  35. }
  36. },
  37. emits: ['change'],
  38. setup(props, { emit }) {
  39. let timer = null as any;
  40. const audioData = reactive({
  41. isFirst: true,
  42. duration: 0,
  43. currentTime: 0
  44. });
  45. const audioRef = ref();
  46. /** 加载成功 */
  47. const onLoadedmetadata = () => {
  48. audioData.duration = audioRef.value.duration;
  49. if (audioData.isFirst) {
  50. audioData.isFirst = false;
  51. return;
  52. }
  53. if (props.playState === 'play') {
  54. audioRef.value.play();
  55. }
  56. };
  57. /** 改变时间 */
  58. const handleChangeTime = (val: number) => {
  59. audioRef.value.pause();
  60. audioData.currentTime = val;
  61. clearTimeout(timer);
  62. timer = setTimeout(() => {
  63. audioRef.value.currentTime = val;
  64. if (props.playState === 'play') {
  65. audioRef.value.play();
  66. }
  67. timer = null;
  68. }, 300);
  69. };
  70. const time = computed(() => {
  71. return `${getSecondRPM(audioData.currentTime)} / ${getSecondRPM(
  72. audioData.duration
  73. )}`;
  74. });
  75. watch(
  76. () => props.playState,
  77. val => {
  78. if (val === 'play') {
  79. audioRef.value.play();
  80. } else {
  81. audioRef.value.pause();
  82. }
  83. }
  84. );
  85. return () => (
  86. <div class={[styles.container, props.show ? styles.show : styles.hidden]}>
  87. <div class={[styles.item]}>
  88. <div class={styles.img}>
  89. <NImage
  90. lazy
  91. objectFit="cover"
  92. previewDisabled={true}
  93. src={props.item.titleImg}
  94. onLoad={e => {
  95. (e.target as any).dataset.loaded = 'true';
  96. }}
  97. />
  98. <svg class={styles.svgcontainer}>
  99. <defs>
  100. <linearGradient id="GradientProgress">
  101. <stop stop-color="#5BECFF" offset="0%" />
  102. <stop stop-color="#259CFE" offset="100%" />
  103. </linearGradient>
  104. </defs>
  105. </svg>
  106. <NProgress
  107. type="circle"
  108. class={styles.progress}
  109. showIndicator={false}
  110. percentage={(audioData.currentTime / audioData.duration) * 100}
  111. />
  112. </div>
  113. <div class={styles.title}>
  114. <div class={styles.titleName}>
  115. <TheNoticeBar text={props.item.musicSheetName} />
  116. </div>
  117. <div class={styles.titleDes}>{props.item.composer}</div>
  118. </div>
  119. <div class={styles.playBtns}>
  120. <NButton
  121. color="rgba(246,246,246,1)"
  122. circle
  123. bordered={false}
  124. onClick={() => emit('change', 'pre')}>
  125. <img src={icon_pre} />
  126. </NButton>
  127. <NButton
  128. color="rgba(57,130,246,1)"
  129. class={styles.playBtn}
  130. circle
  131. bordered={false}
  132. onClick={() =>
  133. emit('change', props.playState === 'pause' ? 'play' : 'pause')
  134. }>
  135. <img
  136. style={{
  137. display: props.playState === 'pause' ? '' : 'none',
  138. transform: 'scale(1.5) translateX(1Px)'
  139. }}
  140. src={icon_play}
  141. />
  142. <img
  143. style={{
  144. display: props.playState === 'play' ? '' : 'none',
  145. transform: 'scale(1.5)'
  146. }}
  147. src={icon_pause}
  148. />
  149. </NButton>
  150. <NButton
  151. color="rgba(246,246,246,1)"
  152. circle
  153. bordered={false}
  154. onClick={() => emit('change', 'next')}>
  155. <img src={icon_next} />
  156. </NButton>
  157. </div>
  158. <div class={styles.timeWrap}>
  159. <NSlider
  160. tooltip={false}
  161. step={0.01}
  162. class={styles.timeProgress}
  163. value={audioData.currentTime}
  164. max={audioData.duration}
  165. onUpdate:value={val => handleChangeTime(val)}
  166. />
  167. <div class={styles.time}>{time.value}</div>
  168. <audio
  169. ref={audioRef}
  170. src={props.item.audioFileUrl}
  171. onLoadedmetadata={onLoadedmetadata}
  172. onTimeupdate={() => {
  173. if (timer) return;
  174. audioData.currentTime = audioRef.value.currentTime;
  175. }}></audio>
  176. </div>
  177. </div>
  178. </div>
  179. );
  180. }
  181. });