AudioLineSentence.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. <template>
  2. <!-- mp3Source && mp3Source == 'tts' ? 'Audio-tts' : '', -->
  3. <div :class="['Audio', 'AudioFull']">
  4. <div
  5. :class="['audioLine3', bgIndex == 1 ? 'audioLine3-green' : '']"
  6. @click="PlayAudio"
  7. >
  8. <div
  9. class="play"
  10. :class="[
  11. audio.loading ? 'loadBtn' : audio.playing ? 'playBtn' : 'pauseBtn'
  12. ]"
  13. />
  14. </div>
  15. <!-- <div :class="['audioLine', bgIndex == 1 ? 'audioLine-green' : '']">
  16. <div
  17. class="play"
  18. :class="[
  19. audio.loading ? 'loadBtn' : audio.playing ? 'playBtn' : 'pauseBtn',
  20. ]"
  21. @click="PlayAudio"
  22. />
  23. <template >
  24. <el-slider
  25. v-model="playValue"
  26. :style="{ width: sliderWidth + 'px', height: '6px' }"
  27. :format-tooltip="formatProcessToolTip"
  28. @change="changeCurrentTime"
  29. />
  30. <span :class="bgIndex == 1 ? 'color-white' : ''">
  31. {{ realFormatSecond(audio.maxTime) }}
  32. </span>
  33. </template>
  34. </div> -->
  35. <!-- <div v-else class="audioLine2">
  36. <div
  37. class="play-icon"
  38. :class="
  39. audio.loading
  40. ? 'loadBtn'
  41. : audio.playing
  42. ? 'playBtn-icon'
  43. : 'pauseBtn-icon'
  44. "
  45. @click="PlayAudio"
  46. />
  47. </div> -->
  48. <audio
  49. :id="audioId"
  50. :ref="audioId"
  51. :src="mp3"
  52. preload="meta"
  53. @loadedmetadata="onLoadedmetadata"
  54. @timeupdate="onTimeupdate"
  55. @canplaythrough="oncanplaythrough"
  56. />
  57. </div>
  58. </template>
  59. <script>
  60. // 这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  61. // 例如:import 《组件名称》from ‘《组件路径》';
  62. export default {
  63. // import引入的组件需要注入到对象中才能使用
  64. components: {},
  65. props: [
  66. "mp3",
  67. "mp3Source",
  68. "getCurTime",
  69. "stopAudio",
  70. "width",
  71. "isRepeat",
  72. "themeColor",
  73. "ed",
  74. "bg",
  75. "audioId",
  76. "maxTime",
  77. "hideSlider",
  78. "bgIndex",
  79. "wordPlay",
  80. "isAuto",
  81. "curTime"
  82. ],
  83. data() {
  84. // 这里存放数据
  85. return {
  86. playValue: 0,
  87. audio: {
  88. // 该字段是音频是否处于播放状态的属性
  89. playing: false,
  90. // 音频当前播放时长
  91. currentTime: 0,
  92. // 音频最大播放时长
  93. maxTime: 0,
  94. isPlaying: false,
  95. loading: false
  96. },
  97. playTime: parseInt(this.maxTime),
  98. audioAllTime: null, // 展示总时间
  99. duioCurrentTime: null, // 剩余时间
  100. count: 0,
  101. loading: null,
  102. playcount: 0
  103. };
  104. },
  105. // 计算属性 类似于data概念
  106. computed: {
  107. sliderWidth() {
  108. let width = 0;
  109. if (this.width) {
  110. width = this.width;
  111. } else {
  112. width = 662;
  113. }
  114. return width;
  115. }
  116. },
  117. // 监控data中数据变化
  118. watch: {
  119. stopAudio: {
  120. handler(val, oldVal) {
  121. const _this = this;
  122. if (val) {
  123. _this.$refs[_this.audioId].pause();
  124. _this.audio.playing = false;
  125. }
  126. },
  127. // 深度观察监听
  128. deep: true
  129. },
  130. "audio.playing": {
  131. handler(val) {
  132. this.$emit("playChange", val);
  133. if (val) this.$emit("handleChangeStopAudio");
  134. }
  135. }
  136. },
  137. // 生命周期 - 创建完成(可以访问当前this实例)
  138. created() {},
  139. // 生命周期 - 挂载完成(可以访问DOM元素)
  140. mounted() {
  141. let _this = this;
  142. _this.$nextTick(() => {
  143. if (_this.wordPlay) {
  144. _this.PlayAudio();
  145. }
  146. if (_this.isAuto) {
  147. _this.PlayAudio();
  148. }
  149. });
  150. let audioId = _this.audioId;
  151. _this.$refs[audioId].addEventListener("loadstart", function() {});
  152. _this.$refs[audioId].addEventListener("play", function() {
  153. _this.audio.playing = true;
  154. _this.audio.loading = false;
  155. });
  156. _this.$refs[audioId].addEventListener("pause", function() {
  157. _this.audio.playing = false;
  158. if (_this.audio.currentTime * 1000 + 500 > _this.ed) {
  159. // _this.$emit("sentPause", true);
  160. _this.playValue = 0;
  161. _this.audio.isPlaying = false;
  162. }
  163. if (_this.wordPlay) {
  164. _this.$emit("changePlayStatus");
  165. _this.audio.isPlaying = false;
  166. }
  167. });
  168. _this.$refs[audioId].addEventListener("ended", function() {
  169. _this.audio.playing = false;
  170. _this.audio.isPlaying = false;
  171. _this.$emit("handleListenRead", false);
  172. });
  173. this.$nextTick(() => {
  174. if (
  175. document.getElementsByClassName("el-slider__button-wrapper").length > 0
  176. ) {
  177. document
  178. .getElementsByClassName("el-slider__button-wrapper")[0]
  179. .addEventListener("mousedown", function() {
  180. _this.$refs[audioId].pause();
  181. _this.audio.playing = false;
  182. });
  183. }
  184. });
  185. },
  186. // 生命周期-挂载之前
  187. beforeMount() {},
  188. // 生命周期-更新之后
  189. updated() {},
  190. // 如果页面有keep-alive缓存功能,这个函数会触发
  191. activated() {},
  192. // 方法集合
  193. methods: {
  194. PlayAudio() {
  195. let audioId = this.audioId;
  196. let audio = document.getElementsByTagName("audio");
  197. if (
  198. audio &&
  199. audio.length > 0 &&
  200. window.location.href.indexOf("GCLS-Learn") == -1
  201. ) {
  202. audio.forEach(item => {
  203. if (item.src == this.mp3) {
  204. if (item.id !== audioId) {
  205. item.pause();
  206. }
  207. } else {
  208. item.pause();
  209. }
  210. });
  211. }
  212. let video = document.getElementsByTagName("video");
  213. if (
  214. video &&
  215. video.length > 0 &&
  216. window.location.href.indexOf("GCLS-Learn") == -1
  217. ) {
  218. video.forEach(vItem => {
  219. vItem.pause();
  220. });
  221. }
  222. this.$set(this.audio, "isPlaying", true);
  223. if (this.audio.playing) {
  224. this.$refs[audioId].pause();
  225. this.audio.playing = false;
  226. this.$emit("handleListenRead", false);
  227. } else {
  228. if (this.count == 0) {
  229. this.audio.loading = true;
  230. this.count++;
  231. }
  232. this.$refs[audioId].play();
  233. if (this.playcount == 0) {
  234. this.onTimeupdateTime(this.bg / 1000);
  235. this.playcount++;
  236. }
  237. this.$emit("handleChangeStopAudio");
  238. this.$emit("handleListenRead", true);
  239. }
  240. },
  241. oncanplaythrough() {
  242. let _this = this;
  243. // setTimeout(() => {
  244. _this.audio.loading = false;
  245. // }, 10000);
  246. },
  247. // 点击 拖拽播放音频
  248. changeCurrentTime(value) {
  249. let audioId = this.audioId;
  250. this.$refs[audioId].play();
  251. this.audio.playing = true;
  252. this.$refs[audioId].currentTime = parseInt(
  253. (value / 100) * this.audio.maxTime
  254. );
  255. },
  256. mousedown() {
  257. let audioId = this.audioId;
  258. this.$refs[audioId].pause();
  259. this.audio.playing = false;
  260. },
  261. // 进度条格式化toolTip
  262. formatProcessToolTip(index) {
  263. index = parseInt((this.audio.maxTime / 100) * index);
  264. return this.realFormatSecond(index);
  265. },
  266. // 音频加载完之后
  267. onLoadedmetadata(res) {
  268. this.audio.maxTime = parseInt(this.maxTime);
  269. // this.audio.maxTime = parseInt(res.target.duration);
  270. // this.playTime = parseInt(this.maxTime);
  271. // this.audioAllTime = this.realFormatSecond(this.audio.maxTime);
  272. },
  273. // 当音频当前时间改变后,进度条也要改变
  274. onTimeupdate(res) {
  275. let _this = this;
  276. let audioId = _this.audioId;
  277. _this.audio.currentTime = res.target.currentTime;
  278. _this.getCurTime(res.target.currentTime);
  279. let time = _this.audio.currentTime - _this.bg / 1000;
  280. _this.playValue = (time / _this.audio.maxTime) * 100;
  281. setTimeout(() => {
  282. if (_this.audio.currentTime * 1000 > _this.ed) {
  283. if (_this.$refs[audioId]) {
  284. _this.$refs[audioId].pause();
  285. _this.playcount = 0;
  286. }
  287. }
  288. }, 50);
  289. },
  290. onTimeupdateTime(res, playFlag) {
  291. if (!res) return;
  292. let audioId = this.audioId;
  293. this.$refs[audioId].currentTime = res;
  294. let time = res - this.bg / 1000;
  295. this.playValue = (time / this.audio.maxTime) * 100;
  296. if (playFlag) {
  297. let audio = document.getElementsByTagName("audio");
  298. if (
  299. audio &&
  300. audio.length > 0 &&
  301. window.location.href.indexOf("GCLS-Learn") == -1
  302. ) {
  303. audio.forEach(item => {
  304. if (item.id !== audioId) {
  305. item.pause();
  306. }
  307. });
  308. }
  309. this.$refs[audioId].play();
  310. }
  311. },
  312. // 将整数转换成 时:分:秒的格式
  313. realFormatSecond(value) {
  314. let theTime = parseInt(value); // 秒
  315. let theTime1 = 0; // 分
  316. let theTime2 = 0; // 小时
  317. if (theTime > 60) {
  318. theTime1 = parseInt(theTime / 60);
  319. theTime = parseInt(theTime % 60);
  320. if (theTime1 > 60) {
  321. theTime2 = parseInt(theTime1 / 60);
  322. theTime1 = parseInt(theTime1 % 60);
  323. }
  324. }
  325. let result = String(parseInt(theTime));
  326. if (result < 10) {
  327. result = "0" + result;
  328. }
  329. if (theTime1 > 0) {
  330. result = String(parseInt(theTime1)) + ":" + result;
  331. if (theTime1 < 10) {
  332. result = "0" + result;
  333. }
  334. } else {
  335. result = "00:" + result;
  336. }
  337. if (theTime2 > 0) {
  338. result = String(parseInt(theTime2)) + ":" + result;
  339. if (theTime2 < 10) {
  340. result = "0" + result;
  341. }
  342. } else {
  343. // result = "00:" + result;
  344. }
  345. return result;
  346. }
  347. },
  348. // 生命周期-创建之前
  349. beforeCreated() {},
  350. // 生命周期-更新之前
  351. beforUpdate() {},
  352. // 生命周期-销毁之前
  353. beforeDestory() {},
  354. // 生命周期-销毁完成
  355. destoryed() {}
  356. };
  357. </script>
  358. <style lang="scss" scoped>
  359. /* @import url(); 引入css类 */
  360. .AudioFull {
  361. .audioLine {
  362. display: flex;
  363. align-items: center;
  364. width: 100%;
  365. height: 40px;
  366. background: #ffffff;
  367. // border: 1px solid rgba(0, 0, 0, 0.1);
  368. // box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.1);
  369. box-sizing: border-box;
  370. border-radius: 4px;
  371. &-green {
  372. background: 0 0;
  373. }
  374. .play {
  375. margin-right: 12px;
  376. margin-left: 8px;
  377. width: 16px;
  378. min-width: 16px;
  379. height: 16px;
  380. cursor: pointer;
  381. display: block;
  382. }
  383. span {
  384. font-size: 16px;
  385. line-height: 19px;
  386. color: #000;
  387. margin-left: 8px;
  388. margin-right: 12px;
  389. font-weight: bold;
  390. font-size: 16px;
  391. line-height: 24px;
  392. text-align: right;
  393. &.color-white {
  394. color: #fff;
  395. }
  396. }
  397. }
  398. .audioLine2 {
  399. .play-icon {
  400. width: 16px;
  401. height: 16px;
  402. cursor: pointer;
  403. &.playBtn-icon {
  404. background: url("../../../assets/icon/pauseC-16-normal-red.png")
  405. no-repeat left top;
  406. background-size: 100% 100%;
  407. }
  408. &.pauseBtn-icon {
  409. background: url("../../../assets/NPC/compare-pause-red.png") no-repeat
  410. left top;
  411. background-size: 100% 100%;
  412. }
  413. }
  414. }
  415. .loadBtn {
  416. background: url("../../../assets/NPC/loading-red.png") no-repeat left top;
  417. background-size: 100% 100%;
  418. }
  419. .audioLine3 {
  420. width: 56px;
  421. height: 56px;
  422. background: #ffffff;
  423. border: 1px solid rgba(0, 0, 0, 0.1);
  424. border-radius: 40px;
  425. display: flex;
  426. justify-content: center;
  427. align-items: center;
  428. .play {
  429. width: 24px;
  430. height: 24px;
  431. cursor: pointer;
  432. &.playBtn {
  433. background: url("../../../assets/icon/pause-24-normal-red.png")
  434. no-repeat left top;
  435. background-size: 100% 100%;
  436. }
  437. &.pauseBtn {
  438. background: url("../../../assets/icon/play-24-normal-red.png") no-repeat
  439. left top;
  440. background-size: 100% 100%;
  441. }
  442. }
  443. &-green {
  444. background: rgba(255, 255, 255, 0.1);
  445. border: 1px solid rgba(0, 0, 0, 0.1);
  446. .play {
  447. &.playBtn {
  448. background: url("../../../assets/icon/pause-24-normal-yellow.png")
  449. no-repeat left top;
  450. background-size: 100% 100%;
  451. }
  452. &.pauseBtn {
  453. background: url("../../../assets/icon/play-24-normal-yellow.png")
  454. no-repeat left top;
  455. background-size: 100% 100%;
  456. }
  457. }
  458. }
  459. }
  460. }
  461. </style>
  462. <style lang="scss">
  463. .AudioFull {
  464. .el-slider__button-wrapper {
  465. position: relative;
  466. z-index: 0;
  467. }
  468. .el-slider__button {
  469. width: 6px;
  470. height: 12px;
  471. border-radius: 6px;
  472. top: 12px;
  473. position: absolute;
  474. }
  475. .el-slider__runway {
  476. margin: 0;
  477. padding: 0;
  478. background: #e5e5e5;
  479. border-radius: 6px;
  480. height: 6px;
  481. }
  482. .el-slider {
  483. position: relative;
  484. }
  485. .el-slider__bar {
  486. height: 6px;
  487. border-radius: 6px 0 0 6px;
  488. background: #de4444;
  489. }
  490. .el-slider__button {
  491. background: #de4444;
  492. border: none;
  493. }
  494. .el-slider__button-wrapper {
  495. width: 25px;
  496. }
  497. .audioLine-green {
  498. .el-slider__bar {
  499. background: #ffc600 !important;
  500. }
  501. .el-slider__button {
  502. background: #ffc600 !important;
  503. }
  504. }
  505. }
  506. .NPC-Book-Sty {
  507. .AudioFull {
  508. .el-slider__bar {
  509. height: 6px;
  510. border-radius: 6px;
  511. background: #de4444;
  512. }
  513. .el-slider__button {
  514. background: #de4444;
  515. border: none;
  516. }
  517. .audioLine-green {
  518. .el-slider__bar {
  519. background: #ffc600 !important;
  520. }
  521. .el-slider__button {
  522. background: #ffc600 !important;
  523. }
  524. }
  525. }
  526. }
  527. .NPC-Big-Book-preview-green {
  528. .AudioFull {
  529. .el-slider__bar {
  530. background: #24b99e !important;
  531. }
  532. .el-slider__button {
  533. background: #24b99e !important;
  534. }
  535. .audioLine-green {
  536. .el-slider__bar {
  537. background: #ffc600 !important;
  538. }
  539. .el-slider__button {
  540. background: #ffc600 !important;
  541. }
  542. }
  543. .audioLine2 {
  544. .play-icon {
  545. &.playBtn-icon {
  546. background: url("../../../assets/icon/pauseC-16-normal-Green.png")
  547. no-repeat left top;
  548. background-size: 100% 100%;
  549. }
  550. &.pauseBtn-icon {
  551. background: url("../../../assets/NPC/compare-pause-green.png")
  552. no-repeat left top;
  553. background-size: 100% 100%;
  554. }
  555. }
  556. }
  557. .loadBtn {
  558. background: url("../../../assets/NPC/loading-green.png") no-repeat left
  559. top;
  560. background-size: 100% 100%;
  561. }
  562. .audioLine3 {
  563. .play {
  564. &.playBtn {
  565. background: url("../../../assets/icon/pause-24-normal-green.png")
  566. no-repeat left top;
  567. background-size: 100% 100%;
  568. }
  569. &.pauseBtn {
  570. background: url("../../../assets/icon/play-24-normal-Green.png")
  571. no-repeat left top;
  572. background-size: 100% 100%;
  573. }
  574. }
  575. &-green {
  576. background: rgba(255, 255, 255, 0.1);
  577. border: 1px solid rgba(0, 0, 0, 0.1);
  578. .play {
  579. &.playBtn {
  580. background: url("../../../assets/icon/pause-24-normal-yellow.png")
  581. no-repeat left top;
  582. background-size: 100% 100%;
  583. }
  584. &.pauseBtn {
  585. background: url("../../../assets/icon/play-24-normal-yellow.png")
  586. no-repeat left top;
  587. background-size: 100% 100%;
  588. }
  589. }
  590. }
  591. }
  592. }
  593. }
  594. .NPC-Big-Book-preview-brown {
  595. .AudioFull {
  596. .el-slider__bar {
  597. background: #bd8865 !important;
  598. }
  599. .el-slider__button {
  600. background: #bd8865 !important;
  601. }
  602. .audioLine-green {
  603. .el-slider__bar {
  604. background: #ffc600 !important;
  605. }
  606. .el-slider__button {
  607. background: #ffc600 !important;
  608. }
  609. }
  610. .audioLine2 {
  611. .play-icon {
  612. &.playBtn-icon {
  613. background: url("../../../assets/icon/pauseC-16-normal-Brown.png")
  614. no-repeat left top;
  615. background-size: 100% 100%;
  616. }
  617. &.pauseBtn-icon {
  618. background: url("../../../assets/NPC/compare-pause-brown.png")
  619. no-repeat left top;
  620. background-size: 100% 100%;
  621. }
  622. }
  623. }
  624. .loadBtn {
  625. background: url("../../../assets/NPC/loading-brown.png") no-repeat left
  626. top;
  627. background-size: 100% 100%;
  628. }
  629. .audioLine3 {
  630. .play {
  631. &.playBtn {
  632. background: url("../../../assets/icon/pause-24-normal-brown.png")
  633. no-repeat left top;
  634. background-size: 100% 100%;
  635. }
  636. &.pauseBtn {
  637. background: url("../../../assets/icon/play-24-normal-Brown.png")
  638. no-repeat left top;
  639. background-size: 100% 100%;
  640. }
  641. }
  642. &-green {
  643. background: rgba(255, 255, 255, 0.1);
  644. border: 1px solid rgba(0, 0, 0, 0.1);
  645. .play {
  646. &.playBtn {
  647. background: url("../../../assets/icon/pause-24-normal-yellow.png")
  648. no-repeat left top;
  649. background-size: 100% 100%;
  650. }
  651. &.pauseBtn {
  652. background: url("../../../assets/icon/play-24-normal-yellow.png")
  653. no-repeat left top;
  654. background-size: 100% 100%;
  655. }
  656. }
  657. }
  658. }
  659. }
  660. }
  661. </style>