MySQL, Oracle, Linux, 软件架构及大数据技术知识分享平台

网站首页 > 精选文章 / 正文

Vue3 终于可以共享自己的屏幕给别人看了!

2025-06-24 14:04 huorong 精选文章 1 ℃ 0 评论

一、实现原理与技术背景

1.1 浏览器媒体能力基础

现代浏览器通过 MediaDevices 接口提供媒体设备访问能力,其中 getDisplayMedia 方法专门用于获取屏幕共享流。该方法会触发用户授权流程,成功后可获得包含屏幕内容的媒体流对象。

1.2 响应式设计目标

我们需要实现以下核心功能:

  • 响应式状态管理: 实时反映屏幕共享状态
  • 自动资源回收: 组件卸载时自动释放媒体资源
  • 错误处理机制: 友好的错误提示与恢复能力
  • 跨浏览器兼容: 统一API差异处理

二、核心实现步骤分解

2.1 响应式状态容器

// 创建响应式状态容器
import { ref, reactive } from 'vue';

const state = reactive({
  stream: null,        // 当前媒体流对象
  isActive: false,     // 是否正在共享
  isSupported: !!navigator.mediaDevices?.getDisplayMedia, // 浏览器支持状态
  error: null          // 错误信息
});

2.2 屏幕捕获核心逻辑

// 启动屏幕共享
async function startCapture(options = { video: true, audio: false }) {
try {
    // 请求屏幕共享权限
    const stream = await navigator.mediaDevices.getDisplayMedia({
      video: {
        displaySurface: 'browser', // 捕获浏览器标签页
        logicalSurface: true,     // 包含滚动区域
        ...options.video
      },
      audio: options.audio
    });

    // 更新响应式状态
    state.stream = stream;
    state.isActive = true;

    // 监听停止事件(用户点击浏览器停止按钮)
    stream.getTracks().forEach(track => {
      track.onended = () => stopCapture();
    });
  } catch (err) {
    handleError(err);
  }
}

// 停止屏幕共享
function stopCapture() {
  state.stream?.getTracks().forEach(track => track.stop());
  state.stream = null;
  state.isActive = false;
}

2.3 视频元素绑定

// 自动绑定媒体流到video元素
export function useVideoBinding(videoRef) {
  watch(() => state.stream, (newStream) => {
    if (videoRef.value && newStream) {
      videoRef.value.srcObject = newStream;
      videoRef.value.play().catch(err => {
        console.error('视频播放失败:', err);
      });
    }
  });
}

三、完整实现代码示例

3.1 屏幕捕获Composable

// screen-capture.js
import { ref, reactive, watch, onUnmounted } from'vue';

// 响应式状态管理
const state = reactive({
  stream: null,
  isActive: false,
  isSupported: checkSupport(),
  error: null
});

// 浏览器支持检测
function checkSupport() {
return !!(
    navigator.mediaDevices &&
    navigator.mediaDevices.getDisplayMedia &&
    window.MediaStream
  );
}

// 错误处理中心
function handleError(error) {
  state.error = {
    name: error.name,
    message: error.message || '屏幕共享失败',
    details: error
  };
console.error('屏幕共享错误:', error);
}

// 启动屏幕共享
async function start(options = {}) {
if (!state.isSupported) {
    throw new Error('当前浏览器不支持屏幕共享');
  }

try {
    const stream = await navigator.mediaDevices.getDisplayMedia({
      video: {
        displaySurface: 'browser',
        logicalSurface: true,
        ...(options.video || {})
      },
      audio: !!options.audio
    });

    // 初始化状态
    state.stream = stream;
    state.isActive = true;
    state.error = null;

    // 自动停止监听
    stream.getTracks().forEach(track => {
      track.onended = () => stop();
    });

    return stream;
  } catch (error) {
    handleError(error);
    throw error;
  }
}

// 停止共享
function stop() {
if (state.stream) {
    state.stream.getTracks().forEach(track => track.stop());
    state.stream = null;
    state.isActive = false;
  }
}

// 自动清理资源
onUnmounted(() => {
  stop();
});

export function useScreenCapture() {
return {
    state,
    start,
    stop
  };
}

3.2 组件集成示例

<template>
  <div class="screen-share">
    <video ref="videoEl" autoplay muted playsinline />
    
    <button @click="toggleShare" :disabled="!state.isSupported">
      {{ state.isActive ? '停止共享' : '开始共享' }}
    </button>
    
    <div v-if="state.error" class="error">
      {{ state.error.message }}
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from'vue';
import { useScreenCapture, useVideoBinding } from'./screen-capture';

const videoEl = ref(null);
const { state, start, stop } = useScreenCapture();

// 自动绑定视频元素
useVideoBinding(videoEl);

const toggleShare = async () => {
if (state.isActive) {
    stop();
  } else {
    try {
      await start({
        video: {
          width: { ideal: 1920 },
          frameRate: { ideal: 30 }
        }
      });
    } catch (error) {
      console.error('共享失败:', error);
    }
  }
};
</script>

Tags:video autoplay

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言