QuestionBody.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <template>
  2. <div v-if="questionDetail" class="question-body" :key="examQuestion.questionId">
  3. <div v-html="questionDetail.text"></div>
  4. <!-- <div v-html="questionDetail.audio"></div> -->
  5. <div v-for="({src, name}, index) in questionDetail.audio" :key="name" class="audio-div">
  6. <audio controls preload="auto" controlsList='nodownload' :key="src" :name="name" :src="src" @play="($event) => played(index, $event)"></audio>
  7. <span>(剩余播放次数:{{examQuestion.limitedPlayTimes -
  8. (allAudioPlayTimes.find(a => a.name === name) || { times: 0 }).times}})</span><br />
  9. </div>
  10. </div>
  11. <div v-else>
  12. 获取试题中...
  13. </div>
  14. </template>
  15. <script>
  16. import { createNamespacedHelpers } from "vuex";
  17. const { mapState, mapMutations } = createNamespacedHelpers("examingHomeModule");
  18. export default {
  19. name: "QuestionBody",
  20. data() {
  21. return { questionDetail: null, audioPlayTimes: null };
  22. },
  23. props: {
  24. questionBody: String,
  25. examQuestion: Object
  26. },
  27. mounted() {
  28. this.parseQuestion();
  29. },
  30. // updated() {
  31. // if (this.questionBody.includes("question-audio")) {
  32. // console.log(this.questionBody);
  33. // this.bindAudioPlay();
  34. // }
  35. // },
  36. methods: {
  37. ...mapMutations(["updateExamQuestion", "updateQuestionAudioPlayTimes"]),
  38. async parseQuestion() {
  39. let question = {};
  40. if (this.questionBody.includes("question-audio")) {
  41. let audioArray = this.questionBody.match(/<a.*?question-audio.*?\/a>/g);
  42. if (!this.examQuestion.audioPlayTimes) {
  43. // 初始化音频播放次数
  44. this.audioPlayTimes = [];
  45. } else {
  46. this.audioPlayTimes = JSON.parse(this.examQuestion.audioPlayTimes);
  47. }
  48. question.text = this.questionBody.replace(
  49. /<a.*?question-audio.*?\/a>/g,
  50. ""
  51. );
  52. // 测试 v-html中含有directive是否生效。结论:不生效
  53. // question.text += "<span v-html='<text>abc</text>'>empty</span>";
  54. // audioArray = audioArray.map((v, i) => {
  55. // const remainTimes =
  56. // this.examQuestion.limitedPlayTimes -
  57. // this.examQuestion.audioPlayTimes[i];
  58. // if (remainTimes <= 0) {
  59. // v = v.replace("<a", "<a disabled"); // disabled不生效,仅仅起标明作用
  60. // v = v.replace(/url=/g, "");
  61. // }
  62. // return `${v}<span>(剩余播放次数:${remainTimes})</span><br/>`;
  63. // });
  64. // question.audio = audioArray
  65. // .join("")
  66. // .replace(/<a/g, "<audio controls controlsList='nodownload'")
  67. // .replace(/url=/g, "src=")
  68. // .replace(/a>/g, "audio>");
  69. // console.log(this.questionBody);
  70. // console.log(this.questionBody.match(/url="[^"]*"/g));
  71. // question.audio = this.questionBody
  72. // .match(/url="[^"]*"/g)
  73. // .map(v => v.replace("url="));
  74. // /question-audio.*?url="[^"]*"/.exec(this.questionBody)
  75. question.audio = [];
  76. let re = /name="([^"]*)".*question-audio.*?url="([^"]*)"/g;
  77. let array1;
  78. while ((array1 = re.exec(this.questionBody)) !== null) {
  79. // console.log(`Found ${array1[0]}. Next starts at ${re.lastIndex}.`);
  80. // console.log(array1[1]);
  81. question.audio.push({ name: array1[1], src: array1[2] });
  82. // console.log(question.audio);
  83. // expected output: "Found foo. Next starts at 9."
  84. // expected output: "Found foo. Next starts at 19."
  85. }
  86. // setTimeout(this.bindAudioPlay.bind(this), 1000);
  87. } else {
  88. question.text = this.questionBody;
  89. question.audio = [];
  90. }
  91. this.questionDetail = question;
  92. },
  93. // bindAudioPlay() {
  94. // const audios = document.getElementsByTagName("audio");
  95. // if (audios.length === 0) {
  96. // // setTimeout(this.bindAudioPlay.bind(this), 1000);
  97. // return;
  98. // }
  99. // [...audios].forEach((audio, index) => {
  100. // console.log("bind audio: order:" + this.examQuestion.order);
  101. // const order = this.examQuestion.order;
  102. // const limitedPlayTimes = this.examQuestion.limitedPlayTimes;
  103. // let audioPlayTimes = this.examQuestion.audioPlayTimes;
  104. // audio.addEventListener("play", () => {
  105. // console.log("开始播放");
  106. // if (limitedPlayTimes - audioPlayTimes <= 0) {
  107. // console.log("无剩余播放次数");
  108. // }
  109. // audioPlayTimes[index] = audioPlayTimes[index] + 1;
  110. // this.updateExamQuestion({
  111. // order: order,
  112. // audioPlayTimes: audioPlayTimes
  113. // });
  114. // });
  115. // audio.addEventListener("ended", () => {
  116. // console.log("结束播放");
  117. // this.parseQuestion(); // 不会死循环,因为这个是音频播放触发的
  118. // });
  119. // });
  120. // },
  121. played(index, $event) {
  122. // $event.target.pause();
  123. const limitedPlayTimes = this.examQuestion.limitedPlayTimes;
  124. let audioPlayTimes = this.audioPlayTimes;
  125. console.log("开始播放");
  126. // console.log($event.target.attributes.name.value);
  127. const name = $event.target.attributes.name.value;
  128. // console.log(name);
  129. const theAudio = audioPlayTimes.find(a => a.name === name);
  130. const playedTimes = (theAudio || { times: 0 }).times;
  131. if (limitedPlayTimes - playedTimes <= 0) {
  132. console.log("无剩余播放次数");
  133. $event.target.pause();
  134. return;
  135. }
  136. // var audio = new Audio($event.target.src);
  137. // audio.play();
  138. if (theAudio) {
  139. theAudio.times = playedTimes + 1;
  140. } else {
  141. this.audioPlayTimes.push({ name: name, times: 1 });
  142. }
  143. this.updateQuestionAudioPlayTimes(name);
  144. }
  145. },
  146. computed: {
  147. ...mapState(["allAudioPlayTimes"])
  148. },
  149. watch: {
  150. questionBody() {
  151. this.parseQuestion();
  152. },
  153. examQuestion() {
  154. this.parseQuestion();
  155. }
  156. }
  157. };
  158. </script>
  159. <style >
  160. .audio-div {
  161. display: flex;
  162. align-items: center;
  163. }
  164. /* .question-body audio {
  165. width: 180px;
  166. } */
  167. .question-body audio::-webkit-media-controls-timeline,
  168. .question-body audio::-webkit-media-controls-timeline-container {
  169. display: none;
  170. }
  171. </style>