123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- <template>
- <span class="a-container" style="display: inline-flex; align-items: center">
- <span v-show="shouldShowAudio" @click.stop="play">
- <Button
- v-if="!playing"
- type="primary"
- shape="circle"
- icon="ios-play"
- :disabled="playCount === 0"
- size="small"
- class="play"
- ></Button>
- <Button
- v-else
- type="primary"
- shape="circle"
- icon="md-pause"
- style="cursor: not-allowed"
- size="small"
- class="pause"
- ></Button>
- </span>
- <span style="padding-left: 2px"> </span>
- <span v-show="shouldShowAudio">
- {{ formatTime(currentTime) }} / {{ formatTime(duration) }}
- </span>
- <span v-if="!shouldShowAudio" style="color: blueviolet">
- 音频下载中{{ downloadPercent }}%
- </span>
- </span>
- </template>
- <script>
- import moment from "moment";
- export default {
- name: "QuestionAudio",
- props: {
- src: {
- type: String,
- required: true,
- },
- name: {
- type: String,
- required: true,
- },
- playCount: {
- type: Number,
- required: true,
- },
- },
- data() {
- return {
- done: false,
- downloadPercent: 0,
- currentTime: 0,
- duration: 0,
- playing: false,
- context: null,
- buffer: null,
- };
- },
- computed: {
- shouldShowAudio() {
- return this.downloadPercent === 100;
- },
- },
- async created() {
- this.loadData();
- },
- beforeDestroy() {
- this.source && this.source.stop();
- if (this.context) {
- this.context.close();
- this.context = null;
- }
- },
- methods: {
- formatTime(seconds) {
- return moment.utc(seconds * 1000).format("mm:ss");
- },
- loadData() {
- this.context = new AudioContext();
- this.buffer;
- const loadDogSound = (url) => {
- var request = new XMLHttpRequest();
- request.open("GET", url, true);
- request.responseType = "arraybuffer";
- // Decode asynchronously
- request.onload = () => {
- this.context.decodeAudioData(
- request.response,
- (buffer) => {
- this.buffer = buffer;
- this.duration = Math.floor(this.buffer.duration);
- this.downloadPercent = 100;
- // console.log("load ... ");
- },
- () => {
- console.log("error load audio");
- }
- );
- };
- request.onprogress = (e) => {
- // console.log(e);
- // console.log(e.loaded / e.total);
- this.downloadPercent = Number((e.loaded / e.total) * 100).toFixed(2);
- };
- request.send();
- };
- loadDogSound(this.src);
- },
- async play() {
- if (this.playCount <= 0) {
- console.log("无播放次数");
- return;
- }
- if (this.playing) {
- console.log("正在播放,无法暂停");
- return;
- }
- this.$emit("played");
- // var audio = new Audio();
- // this.source = this.context.createMediaElementSource(audio); // creates a sound source
- // await this.context.decodeAudioData(this.buffer);
- this.context.close();
- this.context = new AudioContext();
- this.source = this.context.createBufferSource(); // creates a sound source
- this.source.buffer = this.buffer; // tell the source which sound to play
- this.source.connect(this.context.destination); // connect the source to the context's destination (the speakers)
- this.source.start(0); // play the source now
- // audio.play();
- this.playing = true;
- this.currentTime = 0;
- const progress = () => {
- // console.log(context.currentTime, buffer.duration);
- this.currentTime = Math.floor(this.context.currentTime);
- if (this.context.currentTime < this.buffer.duration) {
- requestAnimationFrame(progress);
- } else if (this.context.currentTime >= this.buffer.duration) {
- this.currentTime = 0;
- requestAnimationFrame(progress);
- }
- };
- requestAnimationFrame(progress);
- // note: on older systems, may have to use deprecated noteOn(time);
- this.source.onended = () => {
- // console.log(e, "ended");
- this.playing = false;
- this.currentTime = 0;
- // this.$emit("ended", this.name);
- };
- },
- },
- };
- </script>
- <style scoped>
- .a-container >>> .ivu-btn-small {
- width: 18px !important;
- height: 18px !important;
- font-size: 11px !important;
- margin-bottom: 4px;
- }
- .a-container >>> .ivu-btn-small.play {
- padding-left: 2px !important;
- }
- .a-container >>> .ivu-btn-small.pause {
- padding-left: 0px !important;
- padding-top: 1px !important;
- }
- </style>
|