123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- <template>
- <div :class="['Audio']">
- <div class="audioLine" :class="[]">
- <div
- class="play"
- :class="[
- audio.loading ? 'loadBtn' : audio.playing ? 'playBtn' : 'pauseBtn',
- ]"
- @click="PlayAudio"
- >
- <i class="el-icon-loading" v-if="audio.loading"></i>
- <a class="active" v-if="audio.playing&&!audio.loading"><svg-icon icon-class="pause" className="icon-svg"></svg-icon></a>
- <a v-if="!audio.playing&&!audio.loading"><svg-icon icon-class="play" className="icon-svg"></svg-icon></a>
- </div>
- <span class="time-box"
- ><template v-if="audio.playing">-</template
- >{{
- audio.maxTime
- ? realFormatSecond(audio.maxTime - audio.currentTime)
- : ""
- }}</span
- >
- <el-slider
- v-model="playValue"
- :style="{ width: sliderWidth + 'px', height: '2px' }"
- :format-tooltip="formatProcessToolTip"
- @change="changeCurrentTime"
- />
- <el-dropdown
- trigger="hover"
- placement="top"
- szie="mini"
- @command="handleSpeed"
- >
- <span class="el-dropdown-link">
- <span style="color: #2F3742; cursor: pointer; width: 35px; display:block; text-align: center;">{{playbackRateValue}}</span>
- </span>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item :command="i" v-for="i in 5" :key="i"
- >{{ i * 0.5 }}</el-dropdown-item
- >
- </el-dropdown-menu>
- </el-dropdown>
- <el-dropdown trigger="click" placement="top" szie="mini">
- <span class="el-dropdown-link">
- <svg-icon icon-class="voice" className="icon-voice"></svg-icon>
- </span>
- <el-dropdown-menu slot="dropdown">
- <el-slider
- v-model="sound"
- @input="changeSound"
- vertical
- height="100px"
- >
- </el-slider>
- </el-dropdown-menu>
- </el-dropdown>
- <svg-icon icon-class="repeat" :class="['icon-repeat',isRepeat?'active':'']" @click="changeRepeat"></svg-icon>
- </div>
- <audio
- :id="audioId"
- :ref="audioId"
- :src="mp3"
- preload="metadata"
- @loadedmetadata="onLoadedmetadata"
- @timeupdate="onTimeupdate"
- @canplaythrough="oncanplaythrough"
- />
- </div>
- </template>
- <script>
- // 这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
- // 例如:import 《组件名称》from ‘《组件路径》';
- export default {
- // import引入的组件需要注入到对象中才能使用
- components: {},
- props: [
- "mp3",
- "width",
- "audioId",
- "getCurTime"
- ],
- data() {
- // 这里存放数据
- return {
- playValue: 0,
- audio: {
- // 该字段是音频是否处于播放状态的属性
- playing: false,
- // 音频当前播放时长
- currentTime: 0,
- // 音频最大播放时长
- maxTime: 0,
- isPlaying: false,
- loading: false,
- playbackRate: 1,
- volume: 100
- },
- audioAllTime: null, // 展示总时间
- duioCurrentTime: null, // 剩余时间
- count: 0,
- loading: null,
- isClick: false,
- playbackRateValue: '1x',
- sound: 100,
- isRepeat: false
- };
- },
- // 计算属性 类似于data概念
- computed: {
- sliderWidth() {
- let width = 0;
- if (this.width) {
- width = this.width;
- } else {
- width = 839;
- }
- return width;
- },
- },
- // 监控data中数据变化
- watch: {
- stopAudio: {
- handler(val, oldVal) {
- const _this = this;
- if (val) {
- _this.$refs[_this.audioId].pause();
- _this.audio.playing = false;
- }
- },
- // 深度观察监听
- deep: true,
- },
- "audio.playing": {
- handler(val) {
- this.$emit("playChange", val);
- if (val) this.$emit("handleChangeStopAudio");
- },
- },
- },
- // 生命周期 - 创建完成(可以访问当前this实例)
- created() {},
- // 生命周期 - 挂载完成(可以访问DOM元素)
- mounted() {
- let _this = this;
- let audioId = _this.audioId;
- _this.$refs[audioId].addEventListener("loadstart", function () {});
- _this.$refs[audioId].addEventListener("play", function () {
- _this.audio.playing = true;
- _this.audio.isPlaying = true;
- _this.audio.loading = false;
- });
- _this.$refs[audioId].addEventListener("pause", function () {
- _this.audio.playing = false;
- _this.$emit("handleListenRead", false);
- });
- _this.$refs[audioId].addEventListener("ended", function () {
- _this.audio.playing = false;
- _this.audio.isPlaying = false;
- _this.$emit("handleListenRead", false);
- _this.isClick = false;
- });
- this.$nextTick(() => {
- document
- .getElementsByClassName("el-slider__button-wrapper")[0]
- .addEventListener("mousedown", function () {
- _this.$refs[audioId].pause();
- _this.audio.playing = false;
- });
- });
- },
- // 生命周期-挂载之前
- beforeMount() {},
- // 生命周期-更新之后
- updated() {},
- // 如果页面有keep-alive缓存功能,这个函数会触发
- activated() {},
- // 方法集合
- methods: {
- PlayAudio() {
- let audioId = this.audioId;
- let audio = document.getElementsByTagName("audio");
- audio.forEach((item) => {
- if (item.src == this.mp3) {
- if (item.id !== audioId) {
- item.pause();
- }
- } else {
- item.pause();
- }
- });
- let video = document.getElementsByTagName("video");
- video.forEach((vItem) => {
- vItem.pause();
- });
- if (this.audio.playing) {
- this.$refs[audioId].pause();
- this.audio.playing = false;
- this.$emit("handleListenRead", false);
- this.isClick = false;
- } else {
- if (this.count == 0) {
- this.audio.loading = true;
- this.count++;
- }
- this.$refs[audioId].play();
- this.$emit("handleChangeStopAudio");
- this.$emit("handleListenRead", true);
- this.isClick = true;
- }
- },
- oncanplaythrough() {
- let _this = this;
- // setTimeout(() => {
- _this.audio.loading = false;
- // }, 10000);
- },
- // 点击 拖拽播放音频
- changeCurrentTime(value) {
- let audioId = this.audioId;
- this.$refs[audioId].play();
- this.audio.playing = true;
- this.$refs[audioId].currentTime = parseInt(
- (value / 100) * this.audio.maxTime
- );
- },
- mousedown() {
- let audioId = this.audioId;
- this.$refs[audioId].pause();
- this.audio.playing = false;
- },
- // 进度条格式化toolTip
- formatProcessToolTip(index) {
- index = parseInt((this.audio.maxTime / 100) * index);
- return this.realFormatSecond(index);
- },
- // 音频加载完之后
- onLoadedmetadata(res) {
- console.log(res.target.duration);
- this.audio.maxTime = parseInt(res.target.duration);
- this.audioAllTime = this.realFormatSecond(this.audio.maxTime);
- },
- // 当音频当前时间改变后,进度条也要改变
- onTimeupdate(res) {
- let audioId = this.audioId;
- this.audio.currentTime = res.target.currentTime;
- if(this.getCurTime){
- this.getCurTime(res.target.currentTime);
- }
- if(this.isRepeat){
- if(this.audio.currentTime>=this.audio.maxTime || this.audio.currentTime<=0){
- this.onTimeupdateTime(0,true)
- }
- }
- this.playValue = (this.audio.currentTime / this.audio.maxTime) * 100;
- },
- onTimeupdateTime(res, playFlag) {
- if (!res&&res!=0) return;
- let audioId = this.audioId;
- this.$refs[audioId].currentTime = res;
- this.playValue = (res / this.audio.maxTime) * 100;
- if (playFlag) {
- let audio = document.getElementsByTagName("audio");
- audio.forEach((item) => {
- if (item.id !== audioId) {
- item.pause();
- }
- });
- this.$refs[audioId].play();
- }
- },
- // 将整数转换成 时:分:秒的格式
- realFormatSecond(value) {
- let theTime = parseInt(value); // 秒
- let theTime1 = 0; // 分
- let theTime2 = 0; // 小时
- if (theTime > 60) {
- theTime1 = parseInt(theTime / 60);
- theTime = parseInt(theTime % 60);
- if (theTime1 > 60) {
- theTime2 = parseInt(theTime1 / 60);
- theTime1 = parseInt(theTime1 % 60);
- }
- }
- let result = String(parseInt(theTime));
- if (result < 10) {
- result = "0" + result;
- }
- if (theTime1 > 0) {
- result = String(parseInt(theTime1)) + ":" + result;
- if (theTime1 < 10) {
- result = "0" + result;
- }
- } else {
- result = "00:" + result;
- }
- if (theTime2 > 0) {
- result = String(parseInt(theTime2)) + ":" + result;
- if (theTime2 < 10) {
- result = "0" + result;
- }
- } else {
- // result = "00:" + result;
- }
- return result;
- },
- // 倍速按钮
- handleSpeed(val) {
- let audio = this.$refs[this.audioId];
- audio.playbackRate = val * 0.5;
- this.playbackRateValue = val * 0.5 + 'x'
- },
- // 改变音量
- changeSound(val) {
- let audio = this.$refs[this.audioId];
- audio.volume = val / 100;
- },
- changeRepeat() {
- let _this = this;
- _this.isRepeat = !_this.isRepeat;
- },
- },
- // 生命周期-创建之前
- beforeCreated() {},
- // 生命周期-更新之前
- beforUpdate() {},
- // 生命周期-销毁之前
- beforeDestory() {},
- // 生命周期-销毁完成
- destoryed() {},
- };
- </script>
- <style lang="scss" scoped>
- /* @import url(); 引入css类 */
- .Audio {
- width: 100%;
- .audioLine {
- display: flex;
- align-items: center;
- width: 100%;
- .play {
- cursor: pointer;
- a{
- width: 32px;
- height: 32px;
- display: block;
- text-align: center;
- background: #EEF3FF;
- border-radius: 4px;
- // &:hover,&.active{
- // background: #EEF3FF;
- // border-radius: 4px;
- // }
- }
- .el-icon-loading,.icon-svg{
- color: #175DFF;
- width: 24px;
- height: 24px;
- margin-top: 4px;
- }
- }
- .time-box {
- font-size: 16px;
- line-height: 24px;
- color:#2F3742;
- margin-right: 10px;
- min-width: 66px;
- text-align: right;
- }
- }
- .icon-voice,.icon-repeat{
- width: 24px;
- height: 24px;
- color: #175DFF;
- cursor: pointer;
- flex-shrink: 0;
- }
- .icon-repeat{
- margin: 0 8px;
- color: #D0D3D9;
- &.active{
- color: #175DFF;
- }
- }
- }
- </style>
- <style lang="scss">
- .Audio {
- .el-slider{
- height: 20px !important;
- margin-right: 8px;
- }
- .el-slider__bar {
- height: 20px;
- background: #175DFF;
- border-radius: 20px;
- }
- .el-slider__button {
- background: #175DFF;
- border: none;
- }
- .el-slider__button-wrapper {
- width: 25px;
- }
- .el-slider__button-wrapper {
- position: relative;
- z-index: 0;
- }
- .el-slider__button {
- width: 16px;
- height: 16px;
- top: 17px;
- position: absolute;
- opacity: 0;
- }
- .el-slider__runway {
- margin: 0;
- padding: 0;
- background: #e5e5e5;
- border-radius: 20px;
- height: 20px;
- }
- .el-slider {
- position: relative;
- }
- .el-dropdown{
- margin: 0 8px;
- }
- }
- </style>
|