当前位置: 首页 > wzjs >正文

中国移动门户网站抖音网络营销案例分析

中国移动门户网站,抖音网络营销案例分析,小程序电商平台开发,做网站 用什么空间在浏览器中实现屏幕录制通常使用 MediaStream API 和 MediaRecorder API。下面是一个完整的示例,展示如何在Web页面中录制屏幕,并提供下载功能。 功能 选择屏幕或窗口进行录制开始/暂停/停止录制录制完成后可下载视频 核心技术 navigator.mediaDevice…

在浏览器中实现屏幕录制通常使用 MediaStream API 和 MediaRecorder API。下面是一个完整的示例,展示如何在Web页面中录制屏幕,并提供下载功能。

功能

  • 选择屏幕或窗口进行录制
  • 开始/暂停/停止录制
  • 录制完成后可下载视频

核心技术

  1. navigator.mediaDevices.getDisplayMedia():获取屏幕媒体流

  2. MediaRecorder:录制流并保存为视频文件

界面截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

案例源码:

<template><div class="rdp-recorder" :class="{ 'minimal-ui': minimalUI }"><!-- 悬浮的最小化控制面板 - 适合无感录制 --><div v-if="minimalUI" class="floating-controls"><div class="recording-status"><span class="record-indicator" :class="{ paused: isPaused }"></span><span class="timer">{{ formatTime(recordingTime) }}</span></div><div class="button-group"><buttonv-if="isPaused"class="icon-btn resume-btn"title="继续录制"@click="resumeRecording"></button><buttonv-else-if="isRecording"class="icon-btn pause-btn"title="暂停录制"@click="pauseRecording"></button><buttonv-if="isRecording"class="icon-btn stop-btn"title="停止录制"@click="stopRecording"></button></div><button class="icon-btn expand-btn" title="展开面板" @click="minimalUI = false"></button></div><!-- 完整控制面板 --><div v-else class="full-controls"><div class="panel-header"><h3>RDP会话录制</h3><button class="icon-btn minimize-btn" title="最小化" @click="minimalUI = true"></button></div><div class="controls"><buttonv-if="!isRecording":disabled="!hasSupport"class="btn start-btn"@click="startRDPRecording">开始录制RDP会话</button><template v-else><buttonv-if="!isPaused"class="btn pause-btn"@click="pauseRecording">暂停</button><buttonv-elseclass="btn resume-btn"@click="resumeRecording">继续</button><buttonclass="btn stop-btn"@click="stopRecording">停止录制</button></template></div><div v-if="isRecording" class="recording-info"><div class="recording-status"><span class="record-indicator" :class="{ paused: isPaused }"></span><span>{{ isPaused ? '已暂停' : '正在录制RDP会话...' }}</span></div><div class="timer">{{ formatTime(recordingTime) }}</div></div><div v-if="recordingURL" class="preview"><h3>录制预览</h3><video :src="recordingURL" controls width="100%"></video><button class="btn download-btn" @click="downloadRecording('rdp-recording.webm')">下载录制文件</button></div><div v-if="error" class="error">录制错误: {{ error }}</div><div v-if="!hasSupport" class="no-support">您的浏览器不支持屏幕录制功能</div><div class="settings"><h4>录制设置</h4><div class="checkbox-group"><label><input v-model="autoMinimize" type="checkbox" />开始录制后自动最小化</label></div><div class="checkbox-group"><label><input v-model="recordAudio" type="checkbox" />录制音频</label></div><button class="btn auto-start-btn" @click="autoStartRecording">自动选择RDP窗口录制</button><p class="tip">提示: 自动选择功能需要您在弹出框中选择RDP窗口</p></div></div></div>
</template><script lang="ts" setup>import { ref, onMounted, watch } from 'vue';import { useRDPScreenRecorder } from './useRDPScreenRecorder';// 组件名称定义defineOptions({name: 'RDPRecorderComponent',});// 状态const hasSupport = ref(false);const minimalUI = ref(false);const autoMinimize = ref(true);const recordAudio = ref(true);// 引入录屏功能const {isRecording,isPaused,recordingTime,recordingURL,error,startRecording,autoStartRDPRecording,pauseRecording,resumeRecording,stopRecording,downloadRecording,} = useRDPScreenRecorder();// 检查浏览器支持onMounted(() => {hasSupport.value = !!(navigator.mediaDevices &&navigator.mediaDevices.getDisplayMedia);});// 在录制开始后自动最小化UIwatch(isRecording, (newValue) => {if (newValue && autoMinimize.value) {minimalUI.value = true;}});// 格式化时间显示const formatTime = (seconds: number): string => {const mins = Math.floor(seconds / 60);const secs = seconds % 60;return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;};// 开始RDP会话录制const startRDPRecording = () => {startRecording({videoConstraints: {video: {frameRate: { ideal: 15 },cursor: 'always',displaySurface: 'window', // 窗口模式,便于选择RDP窗口logicalSurface: true,width: { ideal: 1280 },height: { ideal: 720 },},},includeAudio: recordAudio.value,captureApplicationAudio: recordAudio.value,mimeType: 'video/webm;codecs=vp9',});};// 自动开始RDP会话录制const autoStartRecording = () => {autoStartRDPRecording();};
</script><style scoped>.rdp-recorder {position: relative;max-width: 800px;margin: 0 auto;padding: 20px;font-family: Arial, sans-serif;border-radius: 8px;background-color: #fff;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);}.floating-controls {position: fixed;bottom: 20px;right: 20px;display: flex;align-items: center;padding: 8px 12px;background-color: rgba(33, 33, 33, 0.8);border-radius: 50px;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);z-index: 9999;color: white;}.recording-status {display: flex;align-items: center;gap: 8px;}.record-indicator {display: inline-block;width: 10px;height: 10px;border-radius: 50%;background-color: #F44336;animation: blink 1s infinite;}.record-indicator.paused {background-color: #FFC107;animation: none;}.button-group {display: flex;margin: 0 8px;}.icon-btn {background-color: transparent;border: none;color: white;width: 28px;height: 28px;border-radius: 50%;display: flex;align-items: center;justify-content: center;cursor: pointer;margin: 0 2px;font-size: 14px;}.icon-btn:hover {background-color: rgba(255, 255, 255, 0.2);}.minimize-btn, .expand-btn {font-size: 12px;}.panel-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 15px;}.panel-header h3 {margin: 0;}.controls {margin: 20px 0;display: flex;gap: 10px;}.btn {padding: 10px 15px;border: none;border-radius: 4px;cursor: pointer;font-weight: bold;transition: background-color 0.3s;}.start-btn {background-color: #4CAF50;color: white;}.pause-btn {background-color: #FFC107;color: #333;}.resume-btn {background-color: #2196F3;color: white;}.stop-btn {background-color: #F44336;color: white;}.download-btn {background-color: #673AB7;color: white;margin-top: 10px;}.auto-start-btn {background-color: #2196F3;color: white;}.btn:hover {opacity: 0.9;}.btn:disabled {background-color: #cccccc;cursor: not-allowed;}.recording-info {display: flex;align-items: center;justify-content: space-between;margin: 20px 0;padding: 10px;background-color: #f5f5f5;border-radius: 4px;}.timer {font-family: monospace;font-size: 1.2rem;}.floating-controls .timer {font-size: 1rem;}.preview {margin-top: 20px;}.error {color: #F44336;margin: 10px 0;padding: 10px;background-color: #FFEBEE;border-radius: 4px;}.no-support {color: #F44336;margin: 10px 0;padding: 10px;background-color: #FFEBEE;border-radius: 4px;}.settings {margin-top: 20px;padding: 15px;background-color: #f5f5f5;border-radius: 4px;}.settings h4 {margin-top: 0;margin-bottom: 15px;}.checkbox-group {margin-bottom: 10px;}.tip {font-size: 12px;color: #666;margin-top: 10px;}@keyframes blink {0% { opacity: 1; }50% { opacity: 0.4; }100% { opacity: 1; }}
</style>
// useRDPScreenRecorder.ts
import { ref, onUnmounted } from 'vue';export function useRDPScreenRecorder() {const isRecording = ref<boolean>(false);const isPaused = ref<boolean>(false);const recordingTime = ref<number>(0);const recordingURL = ref<string>('');const error = ref<string | null>(null);let mediaRecorder: MediaRecorder | null = null;let recordedChunks: Blob[] = [];let startTime = 0;let timerInterval: number | null = null;let combinedStream: MediaStream | null = null;interface RecordingOptions {videoConstraints?: MediaStreamConstraints;audioConstraints?: MediaStreamConstraints;mimeType?: string;timeslice?: number;includeAudio?: boolean;captureApplicationAudio?: boolean;}// 开始录制屏幕和音频const startRecording = async (options: RecordingOptions = {}) => {const defaultOptions: RecordingOptions = {videoConstraints: {video: {// 针对RDP窗口的优化设置frameRate: { ideal: 15 }, // 降低帧率以减少RDP连接的负担cursor: 'always', // 始终捕获光标displaySurface: 'window', // 优先尝试捕获窗口而非整个屏幕logicalSurface: true, // 捕获逻辑窗口表面而非物理显示width: { ideal: 1920 }, // 设置理想分辨率height: { ideal: 1080 },},},audioConstraints: {audio: {// 音频设置优化echoCancellation: true, // 回声消除noiseSuppression: true, // 噪声抑制autoGainControl: true, // 自动增益控制},},mimeType: 'video/webm;codecs=vp9', // VP9编码器在低带宽环境下表现更好timeslice: 1000, // 每秒获取一次数据includeAudio: true, // 是否包含麦克风音频captureApplicationAudio: true, // 是否尝试捕获应用程序音频};const config = { ...defaultOptions, ...options };recordedChunks = [];error.value = null;try {// 获取屏幕流,用户在选择对话框中应该选择RDP窗口const screenStream = await navigator.mediaDevices.getDisplayMedia(config.videoConstraints);// 处理录制结束screenStream.getVideoTracks()[0].onended = () => {stopRecording();};let streams = [screenStream];// 尝试捕获系统音频(RDP会话中的声音)// 注意:这依赖于浏览器和系统支持,可能不适用于所有环境if (config.captureApplicationAudio) {try {// 在某些浏览器中,系统音频可以通过getDisplayMedia的audio选项获取// 检查是否已经有音频轨道const hasAudioTrack = screenStream.getAudioTracks().length > 0;if (!hasAudioTrack) {console.warn('无法直接捕获RDP会话的系统音频,这在某些浏览器中是正常现象');}} catch (err) {console.warn('捕获系统音频失败:', err);}}// 如果需要麦克风音频,获取麦克风流if (config.includeAudio) {try {const audioStream = await navigator.mediaDevices.getUserMedia(config.audioConstraints);streams.push(audioStream);} catch (err) {console.warn('无法获取麦克风权限,继续仅录制视频', err);}}// 合并流combinedStream = new MediaStream();// 添加所有视频轨道streams.forEach(stream => {stream.getVideoTracks().forEach(track => {combinedStream.addTrack(track);});});// 添加所有音频轨道streams.forEach(stream => {stream.getAudioTracks().forEach(track => {combinedStream.addTrack(track);});});// 创建MediaRecorder,优化RDP场景的录制设置const recorderOptions: MediaRecorderOptions = {};if (config.mimeType) {// 检查MIME类型支持if (MediaRecorder.isTypeSupported(config.mimeType)) {recorderOptions.mimeType = config.mimeType;} else if (MediaRecorder.isTypeSupported('video/webm')) {recorderOptions.mimeType = 'video/webm'; // 降级}}// 可以添加录制质量设置// 对于RDP场景,可以考虑降低视频比特率以减少资源占用// 初始化录制器mediaRecorder = new MediaRecorder(combinedStream, recorderOptions);// 处理数据可用事件mediaRecorder.ondataavailable = (event) => {if (event.data.size > 0) {recordedChunks.push(event.data);}};// 处理录制结束事件mediaRecorder.onstop = () => {const mimeType = mediaRecorder?.mimeType || 'video/webm';const blob = new Blob(recordedChunks, { type: mimeType });recordingURL.value = URL.createObjectURL(blob);isRecording.value = false;if (timerInterval) {clearInterval(timerInterval);timerInterval = null;}};// 开始录制mediaRecorder.start(config.timeslice);isRecording.value = true;isPaused.value = false;startTime = Date.now();// 启动计时器timerInterval = window.setInterval(() => {recordingTime.value = Math.floor((Date.now() - startTime) / 1000);}, 1000);} catch (err: any) {error.value = err.message || '录制失败';console.error('录制失败:', err);}};// 自动开始录制RDP窗口(无感知方式)const autoStartRDPRecording = async () => {try {// 尝试自动开始录制,但需要用户交互触发// 建议在用户点击页面其他地方或进行其他交互后调用await startRecording({videoConstraints: {video: {// 针对RDP会话的优化设置frameRate: { ideal: 10 }, // 降低帧率可减轻网络负担cursor: 'always',displaySurface: 'window', // 设置为窗口模式,方便用户选择RDP窗口logicalSurface: true,// 减少分辨率可以降低CPU使用率width: { ideal: 1280 },height: { ideal: 720 },},},// 降低录制频率,减少资源占用timeslice: 2000,captureApplicationAudio: true,});console.log('RDP录制已自动开始,请在弹出的对话框中选择RDP窗口');} catch (err) {console.error('自动开始RDP录制失败:', err);}};// 暂停录制const pauseRecording = () => {if (mediaRecorder && isRecording.value && !isPaused.value && mediaRecorder.state === 'recording') {mediaRecorder.pause();isPaused.value = true;if (timerInterval) {clearInterval(timerInterval);timerInterval = null;}}};// 继续录制const resumeRecording = () => {if (mediaRecorder && isRecording.value && isPaused.value && mediaRecorder.state === 'paused') {mediaRecorder.resume();isPaused.value = false;// 重启计时器timerInterval = window.setInterval(() => {recordingTime.value = Math.floor((Date.now() - startTime) / 1000);}, 1000);}};// 停止录制const stopRecording = () => {if (mediaRecorder && isRecording.value &&(mediaRecorder.state === 'recording' || mediaRecorder.state === 'paused')) {mediaRecorder.stop();// 停止所有轨道if (combinedStream) {combinedStream.getTracks().forEach(track => track.stop());}if (timerInterval) {clearInterval(timerInterval);timerInterval = null;}}};// 下载录制内容const downloadRecording = (filename = 'rdp-recording.webm') => {if (recordingURL.value) {const a = document.createElement('a');document.body.appendChild(a);a.style.display = 'none';a.href = recordingURL.value;a.download = filename;a.click();document.body.removeChild(a);}};// 清理函数onUnmounted(() => {stopRecording();if (recordingURL.value) {URL.revokeObjectURL(recordingURL.value);}});return {isRecording,isPaused,recordingTime,recordingURL,error,startRecording,autoStartRDPRecording,pauseRecording,resumeRecording,stopRecording,downloadRecording,};
}
http://www.dtcms.com/wzjs/234007.html

相关文章:

  • 开奖网站怎么做网络推广违法吗
  • 湖南建设监理工程网站百度seo推广是什么
  • 信用渭南网站建设营销策划公司主要做些什么
  • 做网站找哪个一个产品的宣传和推广方案
  • 北京市网站建设公司图片在线转外链
  • 网站开发的语言平台推广员是做什么的
  • 阿里云空间做的网站不收录互联网推广方案怎么写
  • 广告装饰 技术支持 东莞网站建设太原seo管理
  • 网站制作公司需要什么资质seo服务内容
  • 做网站最简单seo是干什么的
  • 四川省住房城乡建设厅网站网络搜索词排名
  • 表格网站滚动字体怎么做游戏代理平台哪个好
  • 怎么介绍自己做的网站效果图排名优化哪家好
  • 广州花都网站建设宣传软文范例
  • 武汉网站建设组织seo优化
  • 做视频开头动画网站seo系统推广
  • 河北邯郸手机网站建设网络推广外包公司哪家好
  • 装饰公司 网站模板安卓优化大师app下载安装
  • 江苏兴力建设集团有限公司网站北京营销推广网站建设
  • 中国建设银行企业网站首页网站及推广
  • 济宁营销网站建设长沙seo工作室
  • 写作网站打不开公司网址怎么注册
  • 如果想看网站的收费电影应该怎么做长尾关键词爱站网
  • 网站建设项目采购公告今日新闻最新消息
  • 网站建设与维护书籍优秀企业网站欣赏
  • 开通小程序流程seo入门教程seo入门
  • wordpress大发的微博seo综合查询站长工具怎么用
  • 泰州网站制作价格温州seo教程
  • 织梦网站深圳整站seo
  • 网站域名 空间申请表搜索引擎营销特点是什么