239 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <section class="ai-audio">
 | |
|     <div class="controller" :class="skinClassName">
 | |
|       <el-row :gutter="10" type="flex">
 | |
|         <el-col>
 | |
|           <i class="play-icon" :class="playIcon" @click="play"></i>
 | |
|         </el-col>
 | |
|         <el-col class="play-progress">
 | |
|           <el-slider
 | |
|               :format-tooltip="getDateFormat"
 | |
|               v-model="currentTime"
 | |
|               :max="totalDuration"
 | |
|               @change="audio.currentTime = currentTime">
 | |
|           </el-slider>
 | |
|           <span class="total" v-if="skin === 'flat'">{{ getDateFormat(currentTime) }}</span>
 | |
|           <span class="total" v-else>{{ [getDateFormat(currentTime), getDateFormat(totalDuration)].join('/') }}</span>
 | |
|         </el-col>
 | |
|       </el-row>
 | |
|       <audio
 | |
|           ref="audio"
 | |
|           style="display: none;"
 | |
|           :src="src"
 | |
|           preload="metadata"
 | |
|           @pause="playState = false"
 | |
|           @playing="playing"
 | |
|           @loadedmetadata="loadedmetadata"
 | |
|           @timeupdate="timeupdate"
 | |
|       ></audio>
 | |
|     </div>
 | |
|   </section>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import moment from 'dayjs'
 | |
| 
 | |
| export default {
 | |
|   name: 'AiAudio',
 | |
|   props: {
 | |
|     /**
 | |
|      * 播放资源url
 | |
|      */
 | |
|     src: {
 | |
|       type: String,
 | |
|       required: true,
 | |
|     },
 | |
|     /**
 | |
|      * 同时只允许一个播放
 | |
|      */
 | |
|     singlePlay: {type: Boolean, default: false},
 | |
|     /**
 | |
|      * 播放器风格
 | |
|      * default 旧版样式,flat 新版样式
 | |
|      * @values default,flat
 | |
|      */
 | |
|     skin: {
 | |
|       type: String,
 | |
|       default: 'default'
 | |
|     }
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       audio: null,
 | |
|       playState: false,
 | |
|       currentTime: 0,
 | |
|       totalTime: 0
 | |
|     }
 | |
|   },
 | |
|   computed: {
 | |
|     playIcon() {
 | |
|       if (this.skin === 'flat') {
 | |
|         return this.playState ? 'iconfont iconMediaPlayer_Stop' : 'iconfont iconMediaPlayer_Play'
 | |
|       }
 | |
| 
 | |
|       return this.playState ? 'el-icon-video-pause' : 'el-icon-video-play'
 | |
|     },
 | |
| 
 | |
|     totalDuration() {
 | |
|       return Math.round(this.totalTime)
 | |
|     },
 | |
| 
 | |
|     skinClassName() {
 | |
|       return this.skin === 'default' ? '' : this.skin
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   mounted() {
 | |
|     this.audio = this.$refs.audio
 | |
|   },
 | |
| 
 | |
|   methods: {
 | |
|     play() {
 | |
|       if (this.audio) {
 | |
|         if (this.audio.paused) {
 | |
|           if (this.singlePlay) this.stopAllAudio()
 | |
|           this.audio.play()
 | |
|         } else {
 | |
|           this.audio.pause()
 | |
|         }
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     stopAllAudio() {
 | |
|       let audios = document.getElementsByTagName('audio')
 | |
|       for (let i = 0; i < audios.length; i++) {
 | |
|         if (audios[i]) audios[i].pause()
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     playing() {
 | |
|       this.playState = true
 | |
|     },
 | |
| 
 | |
|     loadedmetadata() {
 | |
|       this.totalTime = this.$refs.audio.duration || 0
 | |
|     },
 | |
| 
 | |
|     getDateFormat(val) {
 | |
|       const time = moment.duration(val, 'seconds')
 | |
|       return [
 | |
|         this.prefixNum(time.minutes(), 2),
 | |
|         this.prefixNum(time.seconds(), 2),
 | |
|       ].join(':')
 | |
|     },
 | |
| 
 | |
|     prefixNum(val, num) {
 | |
|       return (Array(num).join('0') + val).slice(-num)
 | |
|     },
 | |
| 
 | |
|     timeupdate() {
 | |
|       this.currentTime = parseInt(this.audio.currentTime)
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   destroyed() {
 | |
|     this.audio.pause()
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| <style lang="scss" scoped>
 | |
| .ai-audio {
 | |
|   display: flex;
 | |
|   flex: 1;
 | |
| 
 | |
|   .controller {
 | |
|     width: 205px;
 | |
|     height: 40px;
 | |
|     padding: 0 5px;
 | |
|     box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
 | |
|     border-radius: 99px;
 | |
| 
 | |
|     .el-col {
 | |
|       width: auto;
 | |
|     }
 | |
| 
 | |
|     .play-icon {
 | |
|       color: #4c84ff;
 | |
|       cursor: pointer;
 | |
|       line-height: 40px;
 | |
|       font-size: 32px;
 | |
|       transition: color 0.3s;
 | |
| 
 | |
|       &:hover {
 | |
|         color: #b3d8ff;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     .play-progress {
 | |
|       display: flex;
 | |
|       flex: 1;
 | |
| 
 | |
|       .el-slider {
 | |
|         width: 60px;
 | |
|       }
 | |
| 
 | |
|       .total {
 | |
|         margin-left: 15px;
 | |
|         font-size: 12px;
 | |
|         line-height: 40px;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   .flat {
 | |
|     height: 32px;
 | |
|     background: rgba(239, 246, 255, 1);
 | |
|     border: 1px solid rgba(132, 181, 255, 1);
 | |
|     border-radius: 5px;
 | |
|     box-shadow: none;
 | |
| 
 | |
|     .play-icon {
 | |
|       position: relative;
 | |
|       padding-left: 3px;
 | |
|       color: #4c84ff;
 | |
|       cursor: pointer;
 | |
|       line-height: 32px;
 | |
|       font-size: 20px;
 | |
|       transition: color 0.3s;
 | |
| 
 | |
|       &:hover {
 | |
|         color: #b3d8ff;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     :deep(.el-slider__button ){
 | |
|       width: 8px;
 | |
|       height: 8px;
 | |
|       background: #1365DD;
 | |
|     }
 | |
| 
 | |
|     :deep(.el-slider__bar ){
 | |
|       height: 2px;
 | |
|     }
 | |
| 
 | |
|     :deep(.el-slider__button-wrapper ){
 | |
|       height: 32px;
 | |
|     }
 | |
| 
 | |
|     :deep(.el-slider__runway ){
 | |
|       height: 2px;
 | |
|       margin: 15px 0;
 | |
|     }
 | |
| 
 | |
|     .play-progress {
 | |
|       display: flex;
 | |
| 
 | |
|       .el-slider {
 | |
|         width: 84px;
 | |
|       }
 | |
| 
 | |
|       .total {
 | |
|         margin-left: 8px;
 | |
|         font-size: 12px;
 | |
|         line-height: 32px;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| </style>
 |