似琼碧落

前端屏幕录制+字幕生成+智能翻译系统:原生JS vs Vue2 vs Vue3 vs React技术对比

发布时间: 2025年7月28日 04:40作者: 似琼碧落浏览: 137 次
已发布

文章摘要

本文通过实际开发三个功能完全相同的综合应用,深入对比分析了原生JavaScript、Vue2和Vue3在现代Web应用开发中的差异。每个版本都完整实现了屏幕录制(基于MediaDevices API)、字幕生成(基于Web Speech API的实时语音识别)、智能翻译(集成MyMemory、Google Translate、LibreTranslate等多个API)三大核心功能,以及本地存储、文件导出等辅助功能,为开发者选择合适的技术栈提供实用的参考依据。

内容格式: Markdown字数: 42543 字符

📝 摘要

关键词:屏幕录制、语音识别、多语言翻译、MediaDevices API、Web Speech API、Vue.js、前端架构、性能对比


🚀 在线演示

📱 实时体验


🎯 项目背景与目标

在现代Web开发中,屏幕录制功能已成为在线教育、远程协作和内容创作的重要需求。随着浏览器原生API的不断完善,开发者可以使用纯前端技术实现专业级的录屏应用。本文通过构建三个技术栈不同但功能相同的录屏应用,为开发者提供全面的技术选型参考。

🔍 核心功能特性

每个版本都实现了以下三大核心功能及辅助功能:

🎬 屏幕录制功能

  • 基于MediaDevices API的高质量屏幕捕获
  • 支持720p/1080p/480p多种分辨率选择
  • 实时视频预览和录制状态监控
  • 支持系统音频、麦克风音频或混合音频录制

📝 字幕生成功能

  • 基于Web Speech API的实时语音识别
  • 支持中文、英文、日文、韩文等多种语言识别
  • 自动生成带时间戳的字幕文本
  • 连续识别模式,无需手动重启

🌐 智能翻译功能

  • 集成MyMemory、Google Translate、LibreTranslate等多个翻译API
  • 支持10+种目标语言翻译(英语、日语、韩语、法语、德语、西班牙语、俄语、阿拉伯语等)
  • 提供本地翻译选项解决CORS跨域问题
  • 自动重试机制和API智能切换

🛠️ 辅助功能

  • 文件导出:支持视频下载、字幕文件导出和翻译文件导出
  • 本地存储:字幕和翻译内容的本地持久化,支持历史记录恢复
  • 复制功能:一键复制字幕或翻译内容到剪贴板
  • 设置保存:用户偏好设置的自动保存和恢复

📊 技术选型对比概览

特性 原生JavaScript Vue2 + Element UI Vue3 + Element Plus React 18 + Ant Design
开发效率 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
运行性能 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
维护成本 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
学习曲线 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
生态丰富度 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐

🛠️ 技术栈对比分析

📦 核心技术依赖

技术组件 原生JS版本 Vue2版本 Vue3版本 React 18 说明
框架 无框架 Vue.js 2.x Vue.js 3.x React 18 前端框架
UI组件库 原生CSS Element UI Element Plus Ant Design 界面组件
录屏API MediaDevices API MediaDevices API MediaDevices API MediaDevices API 屏幕捕获
音频识别 Web Speech API Web Speech API Web Speech API Web Speech API 语音转文字
文件下载 Blob + URL.createObjectURL Blob + URL.createObjectURL Blob + URL.createObjectURL Blob + URL.createObjectURL 文件处理
数据存储 localStorage localStorage localStorage localStorage 本地存储

🏗️ 架构设计对比

1. 原生JavaScript版本

// 特点:直接操作DOM,面向过程编程
let mediaRecorder = null;
let recordedChunks = [];
let transcriptText = '';

function startRecording() {
    // 直接的函数调用和DOM操作
}

function updateStatus(message, type) {
    // 直接修改DOM元素
    statusInfo.innerHTML = `<strong>系统状态:</strong>${message}`;
}

架构特点

  • 简洁直观:无框架依赖,代码逻辑清晰
  • 性能优秀:无虚拟DOM,直接操作真实DOM
  • 兼容性好:支持所有现代浏览器
  • 维护困难:状态管理分散,代码复用性差
  • 扩展性弱:功能增加时代码结构容易混乱

2. Vue2版本 (Options API)

// 特点:Options API,选项式组织代码
new Vue({
    el: '#app',
    data() {
        return {
            isRecording: false,
            transcriptText: '',
            settings: { /* ... */ }
        }
    },
    methods: {
        async startRecording() {
            // 方法集中管理
        },
        updateStatus(message, type) {
            // 响应式数据驱动
            this.statusMessage = message;
        }
    },
    watch: {
        'settings.language'(newVal) {
            // 监听数据变化
        }
    }
});

架构特点

  • 结构清晰:Options API按功能类型组织代码
  • 响应式强:数据驱动的视图更新
  • 生态丰富:Element UI组件库成熟
  • 学习成本低:API设计直观易懂
  • 逻辑分散:相关逻辑分布在不同选项中
  • TypeScript支持弱:类型推断不够强

3. Vue3版本 (Composition API)

// 特点:Composition API,组合式函数编程
const App = {
    setup() {
        // 响应式数据集中定义
        const isRecording = ref(false);
        const transcriptText = ref('');
        const settings = reactive({ /* ... */ });
        
        // 业务逻辑组合函数
        const useRecording = () => {
            const startRecording = async () => {
                // 逻辑集中管理
            };
            
            return { startRecording };
        };
        
        const { startRecording } = useRecording();
        
        // 监听器
        watch(() => settings.language, (newVal) => {
            // 响应式监听
        });
        
        return {
            isRecording,
            transcriptText,
            settings,
            startRecording
        };
    }
};

架构特点

  • 逻辑集中:相关逻辑可以组织在一起
  • 复用性强:组合函数可以跨组件复用
  • TypeScript友好:更好的类型推断和支持
  • 性能优化:更精确的响应式依赖追踪
  • 现代化:支持最新的JavaScript特性
  • 学习成本高:需要理解Composition API概念
  • 生态迁移:部分Vue2生态需要适配

💻 实际应用界面展示

🖥️ 原生JavaScript版本界面

原生JS版本采用简洁的双栏布局,左侧为控制面板,右侧为视频预览。界面使用纯CSS实现,具有良好的响应式设计:

<div class="container">
    <div class="header">
        <h1>📹 录屏+音频转字幕系统</h1>
        <p>基于原生JavaScript的屏幕录制与实时语音转文字解决方案</p>
    </div>
    <div class="main-content">
        <div class="control-panel">
            <h2 class="section-title">🎮 控制面板</h2>
            <div class="status-info" id="statusInfo">
                <strong>系统状态:</strong>就绪
            </div>
            <button class="btn" id="startBtn" onclick="startRecording()">🎬 开始录制</button>
            <button class="btn btn-danger" id="stopBtn" onclick="stopRecording()" disabled>⏹️ 停止录制</button>
        </div>
        <div class="video-panel">
            <h2 class="section-title">📺 视频预览</h2>
            <div class="video-container">
                <video id="previewVideo" controls></video>
            </div>
        </div>
    </div>
</div>

🎨 Vue2版本界面

Vue2版本使用Element UI组件库,提供了更丰富的交互组件和更专业的视觉效果:

<div id="app">
    <div class="container">
        <div class="header">
            <h1>📹 Vue2录屏+音频转字幕系统</h1>
            <p>基于Vue2 + Element UI的专业录屏与语音识别解决方案</p>
        </div>
        <div class="main-content">
            <!-- 设置面板 -->
            <div class="settings-panel">
                <h2 class="section-title">⚙️ 录制设置</h2>
                <div class="settings-grid">
                    <el-select v-model="settings.videoQuality" placeholder="选择视频质量">
                        <el-option label="720p (推荐)" value="720p"></el-option>
                        <el-option label="1080p (高质量)" value="1080p"></el-option>
                    </el-select>
                    <el-select v-model="settings.language" placeholder="识别语言">
                        <el-option label="中文 (简体)" value="zh-CN"></el-option>
                        <el-option label="English (US)" value="en-US"></el-option>
                    </el-select>
                </div>
            </div>
        </div>
    </div>
</div>

🚀 Vue3版本界面

Vue3版本使用Element Plus,在保持Vue2版本功能的基础上,采用了更现代的组件API和更好的TypeScript支持:

<div id="app">
    <div class="container">
        <div class="header">
            <h1>📹 Vue3录屏+音频转字幕系统</h1>
            <p>基于Vue3 + Element Plus的现代化录屏解决方案</p>
        </div>
        <!-- 使用Composition API的响应式数据绑定 -->
        <el-button type="primary" :icon="VideoCamera" @click="startRecording">
            开始录制
        </el-button>
        <el-progress :percentage="recordingProgress" :format="formatProgress">
        </el-progress>
    </div>
</div>

⚛️ React版本界面

React版本采用Ant Design组件库,整体风格现代,功能区分明确,支持响应式布局:

<div id="root">
  <div className="container">
    <div className="header">
      <h1>📹 React录屏+音频转字幕系统</h1>
      <p>基于React 18 + Ant Design的现代化录屏与语音识别解决方案</p>
    </div>
    <div className="content">
      {/* 控制面板、视频预览、字幕、翻译、设置等区域 */}
    </div>
  </div>
</div>
  • 控制面板:录制、停止、测试语音识别、下载、清空字幕等按钮
  • 视频预览:实时显示录制画面
  • 字幕面板:实时显示识别结果,支持导出/复制/保存/加载
  • 翻译面板:多API选择,目标语言选择,翻译进度提示,导出/复制/保存/加载
  • 设置面板:视频质量、音频源、识别语言、连续识别等

🎯 核心功能实现对比

1. 屏幕录制功能

原生JS实现

async function startRecording() {
    try {
        const stream = await navigator.mediaDevices.getDisplayMedia({
            video: { width: 1280, height: 720, frameRate: 30 },
            audio: true
        });
        
        mediaRecorder = new MediaRecorder(stream);
        mediaRecorder.ondataavailable = function(event) {
            if (event.data.size > 0) {
                recordedChunks.push(event.data);
            }
        };
        
        mediaRecorder.start(1000);
        // 直接更新DOM状态
        document.getElementById('startBtn').disabled = true;
        document.getElementById('stopBtn').disabled = false;
    } catch (err) {
        alert('录制失败: ' + err.message);
    }
}

Vue2实现

methods: {
    async startRecording() {
        try {
            const stream = await navigator.mediaDevices.getDisplayMedia({
                video: this.getVideoConstraints(),
                audio: true
            });
            
            this.stream = stream;
            this.mediaRecorder = new MediaRecorder(stream);
            
            this.mediaRecorder.ondataavailable = (event) => {
                if (event.data.size > 0) {
                    this.recordedChunks.push(event.data);
                }
            };
            
            this.mediaRecorder.start(1000);
            // 响应式数据更新
            this.isRecording = true;
            this.statusMessage = '正在录制中...';
            this.$message.success('录制开始');
        } catch (err) {
            this.$message.error('录制失败: ' + err.message);
        }
    }
}

Vue3实现

const startRecording = async () => {
    try {
        const displayStream = await navigator.mediaDevices.getDisplayMedia({
            video: getVideoConstraints(),
            audio: true
        });

        stream.value = displayStream;
        mediaRecorder.value = new MediaRecorder(stream.value);
        
        mediaRecorder.value.ondataavailable = (event) => {
            if (event.data.size > 0) {
                recordedChunks.value.push(event.data);
            }
        };

        mediaRecorder.value.start(1000);
        // 响应式ref更新
        isRecording.value = true;
        statusMessage.value = '正在录制中...';
        ElMessage.success('录制开始');
    } catch (err) {
        ElMessage.error('录制失败: ' + err.message);
    }
};

React实现

// 录制相关状态
const [mediaRecorder, setMediaRecorder] = useState(null);
const [recordedChunks, setRecordedChunks] = useState([]);
const [stream, setStream] = useState(null);

const startRecording = async () => {
  try {
    setRecordedChunks([]);
    const displayStream = await navigator.mediaDevices.getDisplayMedia({
      video: getVideoConstraints(),
      audio: settings.audioSource === 'system' || settings.audioSource === 'both'
    });
    // ...音频源合并逻辑略
    setStream(displayStream);
    const recorder = new MediaRecorder(displayStream, { mimeType });
    recorder.ondataavailable = (event) => {
      if (event.data.size > 0) setRecordedChunks(prev => [...prev, event.data]);
    };
    recorder.start(1000);
    setMediaRecorder(recorder);
    setIsRecording(true);
    setStartTime(Date.now());
  } catch (err) {
    message.error('开始录制失败: ' + err.message);
  }
};

2. 语音识别功能

原生JS实现

function initSpeechRecognition() {
    if ('webkitSpeechRecognition' in window) {
        const SpeechRecognition = window.webkitSpeechRecognition;
        recognition = new SpeechRecognition();
        
        recognition.onresult = function(event) {
            let finalTranscript = '';
            for (let i = event.resultIndex; i < event.results.length; i++) {
                if (event.results[i].isFinal) {
                    finalTranscript += event.results[i][0].transcript;
                }
            }
            
            if (finalTranscript) {
                const timestamp = getTimestamp();
                transcriptText += `[${timestamp}] ${finalTranscript}\n`;
                // 直接更新DOM
                document.getElementById('transcriptContent').textContent = transcriptText;
            }
        };
        
        return true;
    }
    return false;
}

Vue2实现

methods: {
    initSpeechRecognition() {
        if ('webkitSpeechRecognition' in window) {
            const SpeechRecognition = window.webkitSpeechRecognition;
            this.recognition = new SpeechRecognition();
            
            this.recognition.onresult = (event) => {
                let finalTranscript = '';
                for (let i = event.resultIndex; i < event.results.length; i++) {
                    if (event.results[i].isFinal) {
                        finalTranscript += event.results[i][0].transcript;
                    }
                }
                
                if (finalTranscript) {
                    const timestamp = this.getTimestamp();
                    // Vue2响应式更新
                    this.transcriptText += `[${timestamp}] ${finalTranscript}\n`;
                }
            };
            
            return true;
        }
        return false;
    }
}

Vue3实现

const initSpeechRecognition = () => {
    if ('webkitSpeechRecognition' in window) {
        const SpeechRecognition = window.webkitSpeechRecognition;
        recognition.value = new SpeechRecognition();
        
        recognition.value.onresult = (event) => {
            let finalTranscript = '';
            for (let i = event.resultIndex; i < event.results.length; i++) {
                if (event.results[i].isFinal) {
                    finalTranscript += event.results[i][0].transcript;
                }
            }
            
            if (finalTranscript) {
                const timestamp = getTimestamp();
                // Vue3 ref响应式更新
                transcriptText.value += `[${timestamp}] ${finalTranscript}\n`;
            }
        };
        
        return true;
    }
    return false;
};

React实现

const initSpeechRecognition = () => {
  if (!window.webkitSpeechRecognition && !window.SpeechRecognition) {
    message.error('浏览器不支持语音识别功能');
    return false;
  }
  try {
    const SpeechRecognition = window.webkitSpeechRecognition || window.SpeechRecognition;
    const newRecognition = new SpeechRecognition();
    newRecognition.continuous = settings.continuous;
    newRecognition.interimResults = true;
    newRecognition.lang = settings.language;
    newRecognition.onresult = (event) => {
      let finalTranscript = '';
      for (let i = event.resultIndex; i < event.results.length; i++) {
        if (event.results[i].isFinal) {
          finalTranscript += event.results[i][0].transcript;
        }
      }
      if (finalTranscript) {
        const timestamp = getTimestamp();
        setTranscriptText(prev => prev + `[${timestamp}] ${finalTranscript}\n`);
      }
    };
    setRecognition(newRecognition);
    return true;
  } catch (error) {
    message.error('初始化语音识别失败: ' + error.message);
    return false;
  }
};

3. 多语言翻译功能

所有三个版本都集成了多个翻译API,提供灵活的翻译选择:

翻译API配置

// 支持的翻译服务
const translateApis = {
    localTranslate: {
        url: 'local',
        name: '本地翻译 (无CORS问题)',
        cors: true
    },
    myMemory: {
        url: 'https://api.mymemory.translated.net/get',
        name: 'MyMemory (免费)',
        cors: true
    },
    googleTranslate: {
        url: 'https://translate.googleapis.com/translate_a/single',
        name: 'Google Translate (免费)',
        cors: true
    },
    libreTranslate: {
        url: 'https://libretranslate.de/translate',
        name: 'LibreTranslate (免费)',
        cors: false
    }
};

原生JS翻译实现

async function translateText(text, sourceLang, targetLang) {
    const api = translateApis[currentTranslateApi];

    try {
        let response;
        switch (currentTranslateApi) {
            case 'myMemory':
                const myMemoryUrl = `${api.url}?q=${encodeURIComponent(text)}&langpair=${sourceLang}|${targetLang}`;
                response = await fetch(myMemoryUrl);
                const myMemoryData = await response.json();
                return myMemoryData.responseData.translatedText;

            case 'googleTranslate':
                const googleUrl = `${api.url}?client=gtx&sl=${sourceLang}&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}`;
                response = await fetch(googleUrl);
                const googleData = await response.json();
                return googleData[0][0][0];
        }
    } catch (error) {
        console.error('翻译失败:', error);
        throw error;
    }
}

Vue2翻译实现

// Vue2 methods中的翻译方法
methods: {
    async translateTranscript() {
        if (!this.transcriptText || this.transcriptText === '等待语音输入...') {
            this.$message.warning('没有字幕内容可翻译');
            return;
        }

        this.isTranslating = true;
        this.translationStatus.show = true;
        this.translationStatus.message = '正在翻译...';

        try {
            const lines = this.transcriptText.split('\n').filter(line => line.trim());
            let translatedLines = [];

            for (let i = 0; i < lines.length; i++) {
                const line = lines[i];
                const match = line.match(/^(\[.*?\]) (.*)$/);
                if (match) {
                    const timestamp = match[1];
                    const text = match[2];

                    const translatedText = await this.translateText(text, 'zh', this.translationSettings.targetLanguage);
                    translatedLines.push(`${timestamp} ${translatedText}`);
                }
            }

            this.translationText = translatedLines.join('\n');
            this.translationStatus.message = '翻译完成';
            this.translationStatus.type = 'success';
        } catch (err) {
            this.translationStatus.message = '翻译失败: ' + err.message;
            this.translationStatus.type = 'error';
        } finally {
            this.isTranslating = false;
        }
    }
}

Vue3翻译实现

// Vue3 Composition API中的翻译逻辑
const useTranslation = () => {
    const isTranslating = ref(false);
    const translationText = ref('');
    const translationStatus = reactive({
        show: false,
        message: '',
        type: 'info'
    });

    const translateTranscript = async () => {
        if (!transcriptText.value || transcriptText.value === '等待语音输入...') {
            ElMessage.warning('没有字幕内容可翻译');
            return;
        }

        isTranslating.value = true;
        translationStatus.show = true;
        translationStatus.message = '正在翻译...';

        try {
            const lines = transcriptText.value.split('\n').filter(line => line.trim());
            const translatedLines = [];

            for (const line of lines) {
                const match = line.match(/^(\[.*?\]) (.*)$/);
                if (match) {
                    const [, timestamp, text] = match;
                    const translatedText = await translateText(text, 'zh', targetLanguage.value);
                    translatedLines.push(`${timestamp} ${translatedText}`);
                }
            }

            translationText.value = translatedLines.join('\n');
            translationStatus.message = '翻译完成';
            translationStatus.type = 'success';
        } catch (error) {
            translationStatus.message = '翻译失败: ' + error.message;
            translationStatus.type = 'error';
        } finally {
            isTranslating.value = false;
        }
    };

    return {
        isTranslating,
        translationText,
        translationStatus,
        translateTranscript
    };
};

React翻译实现

const translateText = async (text, sourceLang, targetLang) => {
  const api = translateApis[currentTranslateApi];
  try {
    let response;
    switch (currentTranslateApi) {
      case 'localTranslate':
        if (isLocalFile) return text;
        await new Promise(resolve => setTimeout(resolve, 100));
        return `[本地翻译] ${text}`;
      case 'myMemory':
        const myMemoryUrl = `${api.url}?q=${encodeURIComponent(text)}&langpair=${sourceLang}|${targetLang}`;
        response = await fetch(myMemoryUrl);
        if (!response.ok) throw new Error(`MyMemory API请求失败: ${response.status}`);
        const myMemoryData = await response.json();
        return myMemoryData.responseData.translatedText;
      case 'googleTranslate':
        const googleUrl = `${api.url}?client=gtx&sl=${sourceLang}&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}`;
        response = await fetch(googleUrl);
        if (!response.ok) throw new Error(`Google Translate API请求失败: ${response.status}`);
        const googleData = await response.json();
        return googleData[0][0][0];
      case 'libreTranslate':
        response = await fetch(api.url, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ q: text, source: sourceLang, target: targetLang, format: 'text' })
        });
        if (!response.ok) throw new Error(`LibreTranslate API请求失败: ${response.status}`);
        const libreData = await response.json();
        return libreData.translatedText;
      default:
        throw new Error('未知的翻译API');
    }
  } catch (error) {
    if (currentTranslateApi !== 'localTranslate') {
      setCurrentTranslateApi('localTranslate');
      return await translateText(text, sourceLang, targetLang);
    }
    throw error;
  }
};

4. 数据持久化与本地存储

三个版本都实现了完整的本地数据持久化功能,包括字幕保存、翻译内容保存和用户设置保存:

原生JS存储实现

// 保存字幕到本地存储
function saveTranscript() {
    if (!transcriptText) {
        alert('没有字幕内容可保存');
        return;
    }

    localStorage.setItem('nativeSavedTranscript', transcriptText);
    localStorage.setItem('nativeSavedTranscriptTime', new Date().toISOString());
    alert('字幕已保存到本地存储');
}

// 加载保存的字幕
function loadSavedTranscript() {
    const savedTranscript = localStorage.getItem('nativeSavedTranscript');
    if (savedTranscript) {
        const savedTime = localStorage.getItem('nativeSavedTranscriptTime');
        if (confirm(`发现保存的字幕内容 (${new Date(savedTime).toLocaleString()}),是否恢复?`)) {
            transcriptText = savedTranscript;
            document.getElementById('transcriptContent').textContent = transcriptText;
        }
    }
}

// 导出字幕文件
function exportTranscript() {
    if (!transcriptText) {
        alert('没有字幕内容可导出');
        return;
    }

    const blob = new Blob([transcriptText], { type: 'text/plain;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `native-transcript-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.txt`;
    a.click();
    URL.revokeObjectURL(url);
}

Vue2存储实现

// Vue2 methods中的存储方法
methods: {
    saveTranscript() {
        if (!this.transcriptText) {
            this.$message.warning('没有字幕内容可保存');
            return;
        }

        localStorage.setItem('vue2SavedTranscript', this.transcriptText);
        localStorage.setItem('vue2SavedTranscriptTime', new Date().toISOString());
        this.$message.success('字幕已保存到本地存储');
    },

    loadSavedTranscript() {
        const savedTranscript = localStorage.getItem('vue2SavedTranscript');
        if (savedTranscript) {
            const savedTime = localStorage.getItem('vue2SavedTranscriptTime');
            this.$confirm(`发现保存的字幕内容 (${new Date(savedTime).toLocaleString()}),是否恢复?`, '提示', {
                confirmButtonText: '恢复',
                cancelButtonText: '取消',
                type: 'info'
            }).then(() => {
                this.transcriptText = savedTranscript;
                this.$message.success('字幕内容已恢复');
            });
        }
    },

    exportTranscript() {
        if (!this.transcriptText) {
            this.$message.warning('没有字幕内容可导出');
            return;
        }

        const blob = new Blob([this.transcriptText], { type: 'text/plain;charset=utf-8' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `vue2-transcript-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.txt`;
        a.click();
        URL.revokeObjectURL(url);

        this.$message.success('字幕导出成功');
    }
}

Vue3存储实现

// Vue3 Composition API中的存储逻辑
const useStorage = () => {
    const saveTranscript = () => {
        if (!transcriptText.value) {
            ElMessage.warning('没有字幕内容可保存');
            return;
        }

        localStorage.setItem('vue3SavedTranscript', transcriptText.value);
        localStorage.setItem('vue3SavedTranscriptTime', new Date().toISOString());
        ElMessage.success('字幕已保存到本地存储');
    };

    const loadSavedTranscript = () => {
        const savedTranscript = localStorage.getItem('vue3SavedTranscript');
        if (savedTranscript) {
            const savedTime = localStorage.getItem('vue3SavedTranscriptTime');
            ElMessageBox.confirm(
                `发现保存的字幕内容 (${new Date(savedTime).toLocaleString()}),是否恢复?`,
                '提示',
                {
                    confirmButtonText: '恢复',
                    cancelButtonText: '取消',
                    type: 'info'
                }
            ).then(() => {
                transcriptText.value = savedTranscript;
                ElMessage.success('字幕内容已恢复');
            });
        }
    };

    const exportTranscript = () => {
        if (!transcriptText.value) {
            ElMessage.warning('没有字幕内容可导出');
            return;
        }

        const blob = new Blob([transcriptText.value], { type: 'text/plain;charset=utf-8' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `vue3-transcript-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.txt`;
        a.click();
        URL.revokeObjectURL(url);

        ElMessage.success('字幕导出成功');
    };

    return {
        saveTranscript,
        loadSavedTranscript,
        exportTranscript
    };
};

React存储实现

// 保存字幕
const saveTranscript = () => {
  if (!transcriptText) {
    message.warning('没有字幕内容可保存');
    return;
  }
  localStorage.setItem('reactSavedTranscript', transcriptText);
  localStorage.setItem('reactSavedTranscriptTime', new Date().toISOString());
  message.success('字幕已保存到本地存储');
};
// 加载字幕
const loadSavedTranscript = () => {
  const savedTranscript = localStorage.getItem('reactSavedTranscript');
  if (savedTranscript) {
    const savedTime = localStorage.getItem('reactSavedTranscriptTime');
    if (window.confirm(`发现保存的字幕内容 (${new Date(savedTime).toLocaleString()}),是否恢复?`)) {
      setTranscriptText(savedTranscript);
      message.success('字幕内容已恢复');
    }
  } else {
    message.info('没有找到保存的字幕内容');
  }
};

⚡ 性能对比分析

📊 渲染性能

性能指标 原生JS Vue2 Vue3 React 18 说明
首次渲染 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 初始化速度
更新性能 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 数据变化时的更新
内存占用 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ 运行时内存使用
包体大小 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ 代码文件大小

🔍 详细性能分析

1. 首次加载性能

  • 原生JS: 无框架依赖,加载最快,约50KB
  • Vue2: 需要加载Vue2 + Element UI,约500KB
  • Vue3: 需要加载Vue3 + Element Plus,约600KB
  • React 18: 需要加载React 18 + Ant Design,约100KB

2. 运行时性能

  • 原生JS: 直接DOM操作,无虚拟DOM开销,但手动优化复杂
  • Vue2: 虚拟DOM + Options API,性能良好但有一定开销
  • Vue3: Proxy响应式 + Composition API,性能最优
  • React 18: 虚拟DOM优化成熟,Hooks机制便于性能调优

3. 内存使用

// 原生JS:手动管理,容易内存泄漏
function cleanup() {
    // 需要手动清理事件监听器
    if (recognition) {
        recognition.removeEventListener('result', handleResult);
    }
}

// Vue2:自动清理,但响应式系统有开销
beforeDestroy() {
    // Vue自动清理大部分资源
    if (this.timer) {
        clearInterval(this.timer);
    }
}

// Vue3:更精确的依赖追踪,内存使用更优
onBeforeUnmount(() => {
    // 自动清理 + 手动清理特殊资源
    if (timer.value) {
        clearInterval(timer.value);
    }
});

👥 开发体验对比

🔧 开发效率

开发方面 原生JS Vue2 Vue3 React 18 说明
学习成本 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ 上手难易程度
开发速度 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ 功能实现速度
代码维护 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 长期维护成本
团队协作 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 多人开发友好度
调试体验 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 调试工具支持

💻 代码对比示例

状态管理

// 原生JS:手动管理状态,容易出错
let isRecording = false;
let transcriptText = '';
let settings = {
    language: 'zh-CN',
    continuous: true
};

function updateRecordingStatus(status) {
    isRecording = status;
    // 需要手动更新所有相关DOM元素
    document.getElementById('startBtn').disabled = status;
    document.getElementById('stopBtn').disabled = !status;
    document.getElementById('statusInfo').innerHTML = status ? '录制中...' : '就绪';
}

// Vue2:响应式状态管理
data() {
    return {
        isRecording: false,
        transcriptText: '',
        settings: {
            language: 'zh-CN',
            continuous: true
        }
    }
},
// 模板中自动响应数据变化
// <el-button :disabled="isRecording">开始录制</el-button>

// Vue3:Composition API,逻辑更集中
const isRecording = ref(false);
const transcriptText = ref('');
const settings = reactive({
    language: 'zh-CN',
    continuous: true
});

const toggleRecording = () => {
    isRecording.value = !isRecording.value;
    // 所有依赖这个状态的UI都会自动更新
};

事件处理

// 原生JS:手动绑定事件
document.getElementById('startBtn').addEventListener('click', startRecording);
document.getElementById('language').addEventListener('change', function(e) {
    if (recognition) {
        recognition.lang = e.target.value;
    }
});

// Vue2:声明式事件绑定
// <el-button @click="startRecording">开始录制</el-button>
// <el-select v-model="settings.language" @change="updateLanguage">
watch: {
    'settings.language'(newVal) {
        if (this.recognition) {
            this.recognition.lang = newVal;
        }
    }
}

// Vue3:组合式事件处理
// <el-button @click="startRecording">开始录制</el-button>
watch(() => settings.language, (newVal) => {
    if (recognition.value) {
        recognition.value.lang = newVal;
    }
});

🎨 UI/UX 体验对比

🖼️ 界面设计

1. 原生JS版本

/* 优点:完全自定义样式,灵活性最高 */
.btn {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    border: none;
    padding: 12px 24px;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.3s ease;
}

.btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}

特点

  • ✅ 样式完全可控,可以实现任何设计
  • ✅ 无第三方依赖,加载速度快
  • ❌ 需要手写所有样式,开发工作量大
  • ❌ 响应式适配需要手动处理

2. Vue2 + Element UI

<!-- 优点:成熟的组件库,开发效率高 -->
<el-button type="primary" icon="el-icon-video-camera" @click="startRecording">
    开始录制
</el-button>

<el-progress :percentage="recordingProgress" :format="formatProgress">
</el-progress>

<el-message-box title="提示" message="确认要停止录制吗?">
</el-message-box>

特点

  • ✅ 组件丰富,设计一致性好
  • ✅ 开箱即用,开发效率高
  • ✅ 主题定制能力强
  • ❌ 样式相对固定,深度定制困难
  • ❌ 包体积较大

3. Vue3 + Element Plus

<!-- 优点:现代化组件库,更好的TypeScript支持 -->
<el-button type="primary" :icon="VideoCamera" @click="startRecording">
    开始录制
</el-button>

<el-progress :percentage="recordingProgress" :format="formatProgress">
</el-progress>

<!-- 支持组合式API的更好集成 -->
<el-config-provider :locale="locale">
    <app />
</el-config-provider>

特点

  • ✅ 基于Vue3优化,性能更好
  • ✅ TypeScript支持更完善
  • ✅ 树摇优化,按需引入
  • ✅ 更现代的API设计
  • ❌ 生态相对Vue2较新,某些插件可能不够成熟

🎨 响应式设计

/* 三个版本都支持响应式设计,但实现方式不同 */

/* 原生JS:手写媒体查询 */
@media (max-width: 768px) {
    .main-content {
        grid-template-columns: 1fr;
    }
    .settings-grid {
        grid-template-columns: 1fr;
    }
}

/* Vue2 + Element UI:利用栅格系统 */
<el-row :gutter="20">
    <el-col :xs="24" :sm="12" :md="12" :lg="12">
        <!-- 控制面板 -->
    </el-col>
    <el-col :xs="24" :sm="12" :md="12" :lg="12">
        <!-- 视频面板 -->
    </el-col>
</el-row>

/* Vue3 + Element Plus:现代CSS Grid + 组件 */
<el-row :gutter="20" justify="space-between">
    <el-col :span="12">
        <!-- 使用现代布局特性 -->
    </el-col>
</el-row>

🔧 扩展性与维护性

🧩 代码组织

1. 功能扩展难易度

// 原生JS:添加新功能需要修改多处代码
function addWatermarkFeature() {
    // 1. 添加全局变量
    let watermarkEnabled = false;
    
    // 2. 修改录制函数
    function startRecording() {
        // ... 原有代码
        if (watermarkEnabled) {
            // 添加水印逻辑
        }
    }
    
    // 3. 添加UI元素
    const watermarkBtn = document.createElement('button');
    // ... 手动创建和绑定
}

// Vue2:通过组件和选项扩展
export default {
    mixins: [watermarkMixin], // 使用mixin复用逻辑
    data() {
        return {
            watermarkEnabled: false
        }
    },
    methods: {
        toggleWatermark() {
            this.watermarkEnabled = !this.watermarkEnabled;
        }
    }
}

// Vue3:通过组合函数扩展
const useWatermark = () => {
    const watermarkEnabled = ref(false);
    
    const toggleWatermark = () => {
        watermarkEnabled.value = !watermarkEnabled.value;
    };
    
    return {
        watermarkEnabled,
        toggleWatermark
    };
};

// 在setup中使用
const { watermarkEnabled, toggleWatermark } = useWatermark();

2. 测试友好度

// 原生JS:测试困难,需要模拟DOM
// 难以进行单元测试,主要依赖集成测试

// Vue2:可以测试组件方法
import { mount } from '@vue/test-utils';

test('should start recording when button clicked', async () => {
    const wrapper = mount(RecordingApp);
    await wrapper.find('.start-btn').trigger('click');
    expect(wrapper.vm.isRecording).toBe(true);
});

// Vue3:组合函数可以独立测试
import { useRecording } from './composables/useRecording';

test('useRecording composable', () => {
    const { isRecording, startRecording } = useRecording();
    
    expect(isRecording.value).toBe(false);
    startRecording();
    expect(isRecording.value).toBe(true);
});

🔄 版本升级与迁移

升级路径分析

// Vue2 到 Vue3 迁移示例

// Vue2代码
export default {
    data() {
        return {
            isRecording: false
        }
    },
    methods: {
        startRecording() {
            this.isRecording = true;
        }
    },
    mounted() {
        this.initializeRecording();
    }
}

// Vue3迁移后(兼容语法)
export default {
    data() {
        return {
            isRecording: false
        }
    },
    methods: {
        startRecording() {
            this.isRecording = true;
        }
    },
    mounted() {
        this.initializeRecording();
    }
}

// Vue3现代化重构(Composition API)
export default {
    setup() {
        const isRecording = ref(false);
        
        const startRecording = () => {
            isRecording.value = true;
        };
        
        onMounted(() => {
            initializeRecording();
        });
        
        return {
            isRecording,
            startRecording
        };
    }
}

📈 适用场景分析

🎯 选择建议

1. 原生JS适用场景

  • 轻量级项目:功能简单,对体积要求严格
  • 性能要求极高:需要最大化运行时性能
  • 定制化需求:需要完全控制每个细节
  • 学习目的:深入理解Web API和DOM操作
  • 大型项目:功能复杂,需要团队协作
  • 快速开发:时间紧迫,需要快速交付

2. Vue2适用场景

  • 中型项目:功能中等复杂度
  • 团队熟悉Vue2:现有技术栈和团队经验
  • 稳定性要求:成熟生态,风险较低
  • 兼容性要求:需要支持较老的浏览器
  • 新项目建议:Vue3已经稳定,建议使用新版本
  • TypeScript重度使用:Vue3的TS支持更好

3. Vue3适用场景

  • 新项目首选:最新技术栈,长期维护
  • TypeScript项目:更好的类型支持
  • 大型应用:更好的性能和组织性
  • 现代化要求:使用最新的前端技术
  • 长期项目:考虑未来5年的技术发展
  • 快速原型:如果团队不熟悉Composition API

3. React适用场景

  • 中大型项目:团队熟悉React生态,Ant Design等UI库丰富
  • 需要现代化UI/UX:Ant Design组件库,响应式设计
  • 多端适配:React生态下PWA、桌面端、移动端方案丰富
  • 团队协作:适合多人协作、组件复用
  • 极致性能/极简包体积:原生JS更优
  • SEO极端要求:需配合SSR方案

📊 决策矩阵

考虑因素 权重 原生JS Vue2 Vue3 React 18 说明
开发效率 25% 2 4 4 5 开发速度和易用性
性能表现 20% 5 3 4 4 运行时性能
维护成本 20% 2 4 5 4 长期维护难度
学习成本 15% 3 5 3 4 团队上手难度
生态支持 10% 2 5 4 5 第三方库和工具
未来兼容 10% 3 2 5 4 技术发展趋势

总分计算

  • 原生JS:2.8分
  • Vue2:4.0分
  • Vue3:4.2分
  • React 18:4.1分

🚀 未来发展趋势

📱 技术趋势预测

1. Web标准发展

// 未来可能的新API
// Screen Capture API 增强
const stream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: {
        systemAudio: 'include', // 未来可能支持
        suppressLocalAudioPlayback: true
    },
    // 新的录制选项
    preferCurrentTab: true,
    surfaceSwitching: 'include'
});

// Web Speech API增强
const recognition = new SpeechRecognition({
    // 未来可能的增强功能
    realTimeTranscription: true,
    speakerDiarization: true, // 说话人识别
    emotionDetection: true,   // 情感检测
    languageAutoDetect: true  // 自动语言检测
});

2. 框架发展方向

  • Vue 3.x: 持续优化Composition API,更好的TypeScript集成
  • 原生Web Components: 标准化组件开发,框架无关
  • WebAssembly: 性能关键部分可能使用WASM
  • 边缘计算: 音频处理可能移到边缘节点

3. 开发工具进化

// 未来可能的开发体验
// 1. 更智能的代码生成
// AI辅助的组件生成和优化建议

// 2. 实时性能分析
// 内置的性能监控和优化建议

// 3. 跨平台部署
// 一套代码,部署到Web、桌面、移动端

🎯 最佳实践建议

💡 性能优化

1. 录制优化

// 优化录制性能
const optimizeRecording = {
    // 选择合适的编码格式
    mimeType: 'video/webm;codecs=vp9,opus',
    
    // 控制比特率
    videoBitsPerSecond: 2500000, // 2.5Mbps
    audioBitsPerSecond: 128000,  // 128kbps
    
    // 分段录制,避免内存溢出
    timeslice: 1000 // 每秒保存一次数据
};

// 内存管理
const manageMemory = () => {
    // 及时释放Blob URL
    if (videoUrl) {
        URL.revokeObjectURL(videoUrl);
    }
    
    // 清理事件监听器
    if (mediaRecorder) {
        mediaRecorder.removeEventListener('dataavailable', handleData);
    }
    
    // 停止媒体流
    if (stream) {
        stream.getTracks().forEach(track => track.stop());
    }
};

2. 用户体验优化

// UX最佳实践
const uxOptimizations = {
    // 1. 提供清晰的状态反馈
    showProgress: true,
    showRecordingTime: true,
    showErrorMessages: true,
    
    // 2. 支持键盘快捷键
    shortcuts: {
        'Ctrl+R': 'startRecording',
        'Ctrl+S': 'stopRecording',
        'Ctrl+D': 'downloadVideo'
    },
    
    // 3. 自动保存功能
    autoSave: {
        interval: 30000, // 30秒自动保存
        maxHistory: 10   // 保留最近10次记录
    },
    
    // 4. 无障碍访问
    accessibility: {
        ariaLabels: true,
        keyboardNavigation: true,
        screenReader: true
    }
};

🔒 安全性考虑

// 安全最佳实践
const securityMeasures = {
    // 1. 权限检查
    async checkPermissions() {
        const result = await navigator.permissions.query({name: 'camera'});
        return result.state === 'granted';
    },
    
    // 2. 数据加密存储
    encryptData(data) {
        // 本地存储敏感数据时进行加密
        return CryptoJS.AES.encrypt(data, secretKey).toString();
    },
    
    // 3. 安全的文件下载
    secureDownload(blob, filename) {
        // 验证文件类型和大小
        if (blob.type !== 'video/webm' || blob.size > MAX_FILE_SIZE) {
            throw new Error('Invalid file');
        }
        
        // 使用安全的下载方式
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = sanitizeFilename(filename);
        a.click();
        URL.revokeObjectURL(url);
    }
};

📋 总结与建议

🎯 核心发现

通过实际开发和对比三个版本的屏幕录制应用,我们得出以下关键结论:

1. 开发效率对比

  • React: 开发效率高,Ant Design等UI库丰富,Hooks/函数组件逻辑复用性强,社区活跃
  • Vue2: 开发效率最高,Element UI组件库成熟完善,Options API学习曲线平缓
  • Vue3: 开发效率良好,Composition API提供更好的逻辑组织,但需要适应新的编程范式
  • 原生JS: 开发效率最低,需要手写大量基础功能,但对底层控制最精确

2. 性能表现对比

  • React: 性能优秀,虚拟DOM优化成熟,Hooks机制便于性能调优
  • 原生JS: 运行时性能最优,无框架开销,内存占用最小
  • Vue3: 性能优秀,Proxy响应式系统和优化的虚拟DOM带来显著提升
  • Vue2: 性能良好,但相比Vue3在大量数据更新时略有劣势

3. 维护性对比

  • React: 维护性优秀,函数组件+Hooks逻辑集中,社区最佳实践丰富,易于团队协作
  • Vue3: 维护性最佳,Composition API使逻辑复用和测试更容易
  • Vue2: 维护性良好,但大型项目中Options API可能导致逻辑分散
  • 原生JS: 维护性最差,状态管理复杂,容易产生bug

🚀 实际应用建议

选择原生JavaScript的场景

// 适用于:
const nativeJSScenarios = {
    projectSize: '小型项目(<1000行代码)',
    performance: '对性能要求极高的场景',
    constraints: '严格的包体积限制',
    learning: '深入学习Web API和DOM操作',
    customization: '需要完全自定义的UI和交互'
};

// 示例:嵌入式设备的轻量级录屏工具

选择Vue2的场景

// 适用于:
const vue2Scenarios = {
    projectSize: '中型项目(1000-10000行代码)',
    team: '团队已熟悉Vue2生态',
    stability: '对稳定性要求高的生产环境',
    ecosystem: '需要使用成熟的Vue2插件',
    timeline: '项目时间紧迫,需要快速交付'
};

// 示例:企业内部的录屏培训系统

选择Vue3的场景

// 适用于:
const vue3Scenarios = {
    projectSize: '大型项目(>10000行代码)',
    technology: '新项目,追求最新技术栈',
    typescript: '重度使用TypeScript的项目',
    performance: '对性能有较高要求',
    future: '考虑长期维护和扩展'
};

// 示例:面向未来的在线教育平台

选择React的场景

// 适用于:
const reactScenarios = {
    projectSize: '中大型项目(10000-50000行代码)',
    team: '团队熟悉React生态,Ant Design等UI库丰富',
    ui: '需要现代化UI/UX,Ant Design组件库',
    multiplatform: '多端适配,React生态下PWA、桌面端、移动端方案丰富',
    collaboration: '适合多人协作,组件复用'
};

// 示例:企业内部的录屏培训系统

📈 技术发展趋势预测

短期趋势(1-2年)

  • Vue3生态将逐步完善,成为主流选择
  • 原生Web Components标准化程度提高
  • WebAssembly在音视频处理中的应用增加

中期趋势(3-5年)

  • 浏览器原生API功能进一步增强
  • 边缘计算在实时处理中的应用
  • AI辅助的代码生成和优化工具普及

长期趋势(5年以上)

  • 框架无关的组件开发成为标准
  • 声明式UI编程范式进一步发展
  • 跨平台开发的统一性增强

💡 最佳实践总结

通用最佳实践

  1. 性能优化:合理使用timeslice参数,避免内存泄漏
  2. 错误处理:完善的异常捕获和用户友好的错误提示
  3. 用户体验:提供清晰的状态反馈和进度指示
  4. 安全性:验证用户输入,安全地处理文件下载
  5. 可访问性:支持键盘导航和屏幕阅读器

框架特定最佳实践

原生JavaScript

  • 使用模块化组织代码
  • 实现简单的状态管理模式
  • 注意内存管理和事件监听器清理

Vue2

  • 合理使用mixins复用逻辑
  • 避免在Options API中过度分散相关逻辑
  • 利用Vue DevTools进行调试

Vue3

  • 充分利用Composition API的逻辑复用能力
  • 使用TypeScript增强类型安全
  • 合理拆分组合函数,保持单一职责

React

  • 使用函数组件和Hooks,保持逻辑的集中和可复用性
  • 合理组织组件结构,避免组件嵌套过深
  • 充分利用React DevTools进行调试

🔗 相关资源

📚 技术文档

🛠️ 开发工具

📖 延伸阅读

💴 腾讯语音识别(也是广告)

腾讯云语音

分类:
demo
最后更新: 2025年12月2日 08:22