Record.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <template>
  2. <div
  3. id="record-root"
  4. class="record-root"
  5. >
  6. <iframe
  7. :src="url"
  8. frameborder="0"
  9. />
  10. <button
  11. v-show="isRecording"
  12. class="stop-record"
  13. @click="stopRecord"
  14. >
  15. 结束录屏并分享
  16. </button>
  17. </div>
  18. </template>
  19. <script>
  20. export default {
  21. name: 'NameView',
  22. setup() {
  23. return {
  24. }
  25. },
  26. data() {
  27. return {
  28. mediaRecorder: null,
  29. isRecording: false,
  30. }
  31. },
  32. computed: {
  33. url() {
  34. console.error(decodeURI(this.$route.query.url))
  35. return decodeURI(this.$route.query.url)
  36. }
  37. },
  38. async mounted() {
  39. setTimeout(() => {
  40. const el = document.querySelector('#record-root')
  41. if (el) {
  42. console.log('请求全屏……')
  43. utils.requestFullScreen(el)
  44. } else {
  45. console.log('未请求全屏!')
  46. }
  47. }, 0)
  48. let stream = null
  49. try {
  50. stream = await navigator.mediaDevices.getDisplayMedia({
  51. video: true
  52. })
  53. } catch (error) {
  54. alert('调用录屏功能失败!')
  55. setTimeout(() => {
  56. this.$router.go(-1)
  57. }, 100)
  58. }
  59. // 需要更好的浏览器支持
  60. const mime = MediaRecorder.isTypeSupported("video/webm; codecs=vp9") ?
  61. "video/webm; codecs=vp9" :
  62. "video/webm"
  63. this.mediaRecorder = new MediaRecorder(stream, {
  64. mimeType: mime
  65. })
  66. let chunks = []
  67. this.mediaRecorder.addEventListener('dataavailable', function (e) {
  68. chunks.push(e.data)
  69. })
  70. this.mediaRecorder.addEventListener('stop', () => {
  71. console.log('stoped!')
  72. stream.getTracks().forEach(element => {
  73. element.stop()
  74. })
  75. let blob = new Blob(chunks, {
  76. type: chunks[0].type
  77. })
  78. let url = URL.createObjectURL(blob)
  79. let a = document.createElement('a')
  80. a.href = url
  81. a.download = '录屏'
  82. a.click()
  83. utils.exitFullScreen()
  84. setTimeout(() => {
  85. this.$router.go(-1)
  86. }, 100)
  87. })
  88. this.mediaRecorder.addEventListener('start', () => {
  89. this.isRecording = true
  90. })
  91. this.mediaRecorder.addEventListener('error', (e) => {
  92. console.error(e)
  93. })
  94. // 必须手动启动
  95. this.mediaRecorder.start()
  96. },
  97. beforeUnmount() {
  98. // 可能是用户直接按了后退按钮
  99. if (this.mediaRecorder && this.mediaRecorder.state === 'recording') {
  100. this.mediaRecorder.stop()
  101. }
  102. },
  103. methods: {
  104. stopRecord() {
  105. this.mediaRecorder.stop()
  106. }
  107. }
  108. }
  109. </script>
  110. <style lang="less" scoped>
  111. .record-root {
  112. position: relative;
  113. width: 100%;
  114. height: 100%;
  115. >iframe {
  116. position: absolute;
  117. left: 0;
  118. top: 0;
  119. width: 100%;
  120. height: 100%;
  121. }
  122. >button.stop-record {
  123. position: absolute;
  124. left: 50%;
  125. transform: translateX(-50%);
  126. bottom: 130px;
  127. background: #3b3d44;
  128. border: 1px solid #FFFFFF;
  129. font-family: Source Han Sans CN-Light, Source Han Sans CN;
  130. color: #FFFFFF;
  131. font-size: 16px;
  132. padding: 11px 40px;
  133. border-radius: 20px;
  134. }
  135. }
  136. .mobile {
  137. .record-root {
  138. position: relative;
  139. width: 100%;
  140. height: 100%;
  141. >iframe {
  142. position: absolute;
  143. left: 0;
  144. top: 0;
  145. width: 100%;
  146. height: 100%;
  147. }
  148. >button.stop-record {
  149. position: absolute;
  150. left: 50%;
  151. transform: translateX(-50%);
  152. bottom: calc(130 / 1080 * 83vh);
  153. background: #3b3d44;
  154. border: 1px solid #FFFFFF;
  155. font-family: Source Han Sans CN-Light, Source Han Sans CN;
  156. color: #FFFFFF;
  157. font-size: calc(16 / 1080 * 83vh);
  158. padding: calc(11 / 1080 * 83vh) calc(40 / 1080 * 83vh);
  159. border-radius: calc(20 / 1080 * 83vh);
  160. }
  161. }
  162. }
  163. </style>