vue3实现录音与录像上传功能
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
录音
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import useInject from '@/utils/useInject';
const props: any = defineProps<{
params?: any;
}>();
const recObj: any = reactive({
blob: null,
});
const { $global, $fn } = useInject();
const recBtnDom: any = ref(null);
const playerDom: any = ref(null);
onMounted(() => {
// microphone 麦克风权限
// camera 相机权限
// geolocation 地理位置信息
// notifications 网站显示桌面通知权限
// navigator.mediaDevices.getUserMedia({ audio: true }).then() 麦克风权限
// navigator.mediaDevices.getUserMedia({ video: true }).then() 摄像头权限
// navigator.geolocation.getCurrentPosition(callback) 地理位置权限
// Notification.requestPermission().then() 通知权限
navigator.permissions.query({ name: 'microphone' }).then((res) => {
if (res.state === 'granted') {
// $global.tipsfn({ type: 'ok', con: '已授权录音' });
}else{
}
});
if (navigator.mediaDevices?.getUserMedia) {
let chunks: any = [];
const constraints = { audio: true };
navigator.mediaDevices.getUserMedia(constraints).then(
(stream) => {
console.log('授权成功!');
const mediaRecorder = new MediaRecorder(stream);
$fn.As.stopTouch(recBtnDom.value);
recBtnDom.value.onpointerdown = () => {
if (mediaRecorder.state === 'recording') {
mediaRecorder.stop();
recBtnDom.value.textContent = 'record';
$global.tipsfn({ type: 'ok', con: '录音结束!' });
} else {
mediaRecorder.start();
$global.tipsfn({ type: 'ok', con: '录音中...' });
recBtnDom.value.textContent = 'stop';
}
console.log('录音器状态:', mediaRecorder.state);
};
mediaRecorder.ondataavailable = (e: any) => {
chunks.push(e.data);
};
mediaRecorder.onstop = (e: any) => {
recObj.blob = new Blob(chunks, {
type: 'audio/ogg; codecs=opus',
});
console.log(666.10001, '录音文件blob', chunks, recObj.blob);
chunks = [];
var audioURL = window.URL.createObjectURL(recObj.blob);
playerDom.value.src = audioURL;
};
},
() => {
$global.tipsfn({ type: 'err', con: '授权失败!' });
}
);
} else {
$global.tipsfn({ type: 'err', con: '浏览器不支持 getUserMedia' });
}
});
function uprec() {
if (recObj.blob) {
var reader = new FileReader();
reader.readAsDataURL(recObj.blob);
reader.onload = function () {
$fn.useApiFiles()
.request({
data: {
dir: 'chat/chat',
uid: $fn.As.Uuid('CR'),
ext: '.ogg',
data: reader.result,
},
})
.then((res: any) => {
console.log(666.789, res);
props?.params?.fn(res);
})
.catch((err: any) => {
$global.tipsfn({ type: 'err', con: err });
});
};
}
}
</script>
<template>
<div class="as-ogg-area">
<div class="as-ogg-show-area">
<audio ref="playerDom" controls></audio>
</div>
<div class="as-btn-area">
<button ref="recBtnDom">record</button>
<button @click="uprec">提交</button>
</div>
</div>
</template>
<style scoped>
.as-ogg-area {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.as-ogg-show-area {
flex-grow: 1;
width: 100%;
height: 100%;
overflow: hidden;
}
.as-ogg-show-area > audio {
width: 100%;
height: 100%;
}
.as-btn-area {
text-align: center;
height: auto;
}
.as-btn-area > button {
user-select: none;
padding: 5px 12px;
margin: 15px 5px 0 5px;
}
</style>
录像
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import useInject from '@/utils/useInject';
const props: any = defineProps<{
params?: any;
}>();
const { $global, $fn } = useInject();
const webmObj: any = reactive({
stat: 0,
blob: null,
dataChunks: [],
newRecorder: null,
});
const startBtn: any = ref(null);
const stopBtn: any = ref(null);
const downBtn: any = ref(null);
const preVideo: any = ref(null);
const recVideo: any = ref(null);
onMounted(() => {
navigator.permissions.query({ name: 'camera' }).then((res) => {
if (res.state === 'denied') {
// $global.tipsfn({ type: 'err', con: '已拒绝授权录像' });
}
});
// 开始录制
function startRecording(stream: any, lengthInMS: any = null) {
webmObj.newRecorder = new MediaRecorder(stream);
webmObj.newRecorder.ondataavailable = (event: any) => {
let data = event.data;
webmObj.dataChunks.push(data);
};
webmObj.newRecorder.start(1000);
console.log(webmObj.newRecorder.state + ' start to recording .....');
}
stopBtn.value.addEventListener('pointerdown', () => {
webmObj.stat = 0;
// close the recording
recVideo.value.srcObject
.getTracks()
.forEach((track: any) => track.stop());
webmObj.newRecorder.stop();
// Play recorded video
webmObj.blob = new Blob(webmObj.dataChunks, { type: 'video/webm' });
console.log(
666.30003,
'视频数据Blob',
webmObj.dataChunks,
webmObj.blob
);
preVideo.value.src = URL.createObjectURL(webmObj.blob);
// Save download video, click the download button, you can download it
downBtn.value.href = preVideo.value.src;
downBtn.value.download = 'RecordedVideo.webm';
});
startBtn.value.addEventListener('pointerdown', () => {
webmObj.stat = 1;
// get the stream
navigator.mediaDevices
.getUserMedia({
audio: true,
video: true,
})
.then((stream) => {
// set the stream to left video
recVideo.value.srcObject = stream;
// set the stream to <a> for download
downBtn.value.href = stream;
// captureStream: which is streaming a real-time capture of the content being rendered in the media element.
// A MediaStream object which can be used as a source for audio or video data by other media
recVideo.value.captureStream =
recVideo.value.captureStream ||
recVideo.value.mozCaptureStream;
startRecording(recVideo.value.captureStream());
})
.catch((err) => {
console.log('recording error: ', err);
});
});
});
function upvideo() {
if (webmObj.blob) {
var reader = new FileReader();
reader.readAsDataURL(webmObj.blob);
reader.onload = function () {
$fn.useApiFiles()
.request({
data: {
dir: 'chat/chat',
uid: $fn.As.Uuid('CV'),
ext: '.webm',
data: reader.result,
},
})
.then((res: any) => {
console.log(666.789, res);
props?.params?.fn(res);
})
.catch((err: any) => {
$global.tipsfn({ type: 'err', con: err });
});
};
}
}
</script>
<template>
<div class="as-webm-area">
<div class="as-webm-show-area">
<video v-show="!webmObj.stat" ref="preVideo" controls></video>
<video v-show="webmObj.stat" ref="recVideo" autoplay muted></video>
</div>
<div class="as-btn-area">
<button ref="startBtn">开始录制</button>
<button ref="stopBtn">停止录制</button>
<button ref="downBtn">下载</button>
<button @click="upvideo">提交保存</button>
</div>
</div>
</template>
<style scoped>
.as-webm-area {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.as-webm-show-area {
flex-grow: 1;
width: 100%;
height: 100%;
overflow: hidden;
}
.as-webm-show-area > video {
width: 100%;
height: 100%;
}
.as-btn-area {
text-align: center;
height: auto;
}
.as-btn-area > button {
user-select: none;
padding: 5px 12px;
margin: 15px 5px 0 5px;
}
</style>
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献2条内容
所有评论(0)