voice.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <view>
  3. <page-head :title="title"></page-head>
  4. <view class="uni-padding-wrap">
  5. <block v-if="!recording && !playing && !hasRecord">
  6. <view class="page-body-time">
  7. <text class="time-big">{{formatedRecordTime}}</text>
  8. </view>
  9. <view class="page-body-buttons">
  10. <view class="page-body-button"></view>
  11. <view class="page-body-button" @click="startRecord">
  12. <image src="../../../static/record.png"></image>
  13. </view>
  14. <view class="page-body-button"></view>
  15. </view>
  16. </block>
  17. <block v-if="recording === true">
  18. <view class="page-body-time">
  19. <text class="time-big">{{formatedRecordTime}}</text>
  20. </view>
  21. <view class="page-body-buttons">
  22. <view class="page-body-button"></view>
  23. <view class="page-body-button" @click="stopRecord">
  24. <view class="button-stop-record"></view>
  25. </view>
  26. <view class="page-body-button"></view>
  27. </view>
  28. </block>
  29. <block v-if="hasRecord === true && playing === false">
  30. <view class="page-body-time">
  31. <text class="time-big">{{formatedPlayTime}}</text>
  32. <text class="time-small">{{formatedRecordTime}}</text>
  33. </view>
  34. <view class="page-body-buttons">
  35. <view class="page-body-button" @click="playVoice">
  36. <image src="../../../static/play.png"></image>
  37. </view>
  38. <view class="page-body-button" @click="clear">
  39. <image src="../../../static/trash.png"></image>
  40. </view>
  41. </view>
  42. </block>
  43. <block v-if="hasRecord === true && playing === true">
  44. <view class="page-body-time">
  45. <text class="time-big">{{formatedPlayTime}}</text>
  46. <text class="time-small">{{formatedRecordTime}}</text>
  47. </view>
  48. <view class="page-body-buttons">
  49. <view class="page-body-button" @click="stopVoice">
  50. <image src="../../../static/stop.png"></image>
  51. </view>
  52. <view class="page-body-button" @click="clear">
  53. <image src="../../../static/trash.png"></image>
  54. </view>
  55. </view>
  56. </block>
  57. </view>
  58. </view>
  59. </template>
  60. <script>
  61. // #ifdef APP-PLUS
  62. import permision from "@/common/permission.js"
  63. // #endif
  64. import * as util from '../../../common/util.js'
  65. var playTimeInterval = null;
  66. var recordTimeInterval = null;
  67. var recorderManager = null;
  68. var music = null;
  69. export default {
  70. data() {
  71. return {
  72. title: 'start/stopRecord、play/stopVoice',
  73. recording: false, //录音中
  74. playing: false, //播放中
  75. hasRecord: false, //是否有了一个
  76. tempFilePath: '',
  77. recordTime: 0,
  78. playTime: 0,
  79. formatedRecordTime: '00:00:00', //录音的总时间
  80. formatedPlayTime: '00:00:00' //播放录音的当前时间
  81. }
  82. },
  83. onUnload: function() {
  84. this.end();
  85. },
  86. onLoad: function() {
  87. music = uni.createInnerAudioContext();
  88. music.onEnded(() => {
  89. clearInterval(playTimeInterval)
  90. var playTime = 0
  91. console.log('play voice finished')
  92. this.playing = false;
  93. this.formatedPlayTime = util.formatTime(playTime);
  94. this.playTime = playTime;
  95. });
  96. recorderManager = uni.getRecorderManager();
  97. recorderManager.onStart(() => {
  98. console.log('recorder start');
  99. this.recording = true;
  100. recordTimeInterval = setInterval(() => {
  101. this.recordTime += 1;
  102. this.formatedRecordTime = util.formatTime(this.recordTime);
  103. }, 1000)
  104. });
  105. recorderManager.onStop((res) => {
  106. console.log('on stop');
  107. music.src = res.tempFilePath;
  108. this.hasRecord = true;
  109. this.recording = false;
  110. });
  111. recorderManager.onError(() => {
  112. console.log('recorder onError');
  113. });
  114. },
  115. methods: {
  116. async startRecord() { //开始录音
  117. // #ifdef APP-PLUS
  118. let status = await this.checkPermission();
  119. if (status !== 1) {
  120. return;
  121. }
  122. // #endif
  123. // TODO ios 在没有请求过权限之前无法得知是否有相关权限,这种状态下需要直接调用录音,但没有状态或回调判断用户拒绝
  124. recorderManager.start({
  125. format: 'mp3'
  126. });
  127. },
  128. stopRecord() { //停止录音
  129. recorderManager.stop();
  130. clearInterval(recordTimeInterval);
  131. },
  132. playVoice() {
  133. console.log('play voice');
  134. this.playing = true;
  135. playTimeInterval = setInterval(() => {
  136. this.playTime += 1;
  137. this.formatedPlayTime = util.formatTime(this.playTime);
  138. }, 1000)
  139. music.play();
  140. },
  141. stopVoice() {
  142. clearInterval(playTimeInterval)
  143. this.playing = false;
  144. this.formatedPlayTime = util.formatTime(0);
  145. this.playTime = 0;
  146. music.stop();
  147. },
  148. end() {
  149. music.stop();
  150. recorderManager.stop();
  151. clearInterval(recordTimeInterval)
  152. clearInterval(playTimeInterval);
  153. this.recording = false, this.playing = false, this.hasRecord = false;
  154. this.playTime = 0, this.recordTime = 0;
  155. this.formatedRecordTime = "00:00:00", this.formatedRecordTime = "00:00:00";
  156. },
  157. clear() {
  158. this.end();
  159. }
  160. // #ifdef APP-PLUS
  161. ,
  162. async checkPermission() {
  163. let status = permision.isIOS ? await permision.requestIOS('record') :
  164. await permision.requestAndroid('android.permission.RECORD_AUDIO');
  165. if (status === null || status === 1) {
  166. status = 1;
  167. } else if (status === 2) {
  168. uni.showModal({
  169. content: "系统麦克风已关闭",
  170. confirmText: "确定",
  171. showCancel: false,
  172. success: function(res) {
  173. }
  174. })
  175. } else {
  176. uni.showModal({
  177. content: "需要麦克风权限",
  178. confirmText: "设置",
  179. success: function(res) {
  180. if (res.confirm) {
  181. permision.gotoAppSetting();
  182. }
  183. }
  184. })
  185. }
  186. return status;
  187. }
  188. // #endif
  189. }
  190. }
  191. </script>
  192. <style>
  193. image {
  194. width: 150rpx;
  195. height: 150rpx;
  196. }
  197. .page-body-wrapper {
  198. justify-content: space-between;
  199. flex-grow: 1;
  200. margin-bottom: 300rpx;
  201. }
  202. .page-body-time {
  203. display: flex;
  204. flex-direction: column;
  205. align-items: center;
  206. }
  207. .time-big {
  208. font-size: 60rpx;
  209. margin: 20rpx;
  210. }
  211. .time-small {
  212. font-size: 30rpx;
  213. }
  214. .page-body-buttons {
  215. margin-top: 60rpx;
  216. display: flex;
  217. justify-content: space-around;
  218. }
  219. .page-body-button {
  220. width: 250rpx;
  221. text-align: center;
  222. }
  223. .button-stop-record {
  224. width: 110rpx;
  225. height: 110rpx;
  226. border: 20rpx solid #fff;
  227. background-color: #f55c23;
  228. border-radius: 130rpx;
  229. margin: 0 auto;
  230. }
  231. </style>