Vue3 大屏项目投屏功能开发:多显示器适配实践

Vue3 大屏项目投屏功能开发:多显示器适配实践

近期开发大屏项目时,遇到一个特殊需求:在不同显示器上展示项目的不同页面。最初我对这个需求持怀疑态度,毕竟浏览器访问系统显示器参数并非常规操作。但查阅资料后发现,国外开发者已通过原生 HTML 实现类似功能,于是参考相关方案,将其适配到 Vue3 项目中,最终实现了多显示器投屏效果。

一、核心依赖:Window Management API

投屏功能的实现依赖浏览器的 Window Management API,该 API 能获取多屏幕详细信息、监听屏幕状态变化,还能控制窗口在指定屏幕的位置与尺寸。不过使用前需先确认浏览器兼容性,目前该 API 仅支持 Chrome 等现代浏览器,且要求项目运行在localhost或 HTTPS 环境下。

关键兼容性判断代码如下:

javascript 复制代码
import { ElMessage } from 'element-plus'

window.addEventListener('load', async () => {
  // 检查API支持情况
  if (!('getScreenDetails' in self) || !('isExtended' in screen) || !('onchange' in screen)) {
    ElMessage.error('当前浏览器版本不支持投屏功能')
    return
  }
  // 后续初始化逻辑...
})

二、核心逻辑:权限与屏幕信息管理

1. 权限申请与监听

使用 Window Management API 前,需获取窗口管理权限。通过navigator.permissions.query申请权限,并监听权限状态变化,确保功能正常使用:

javascript 复制代码
let permissionStatus = null // 存储权限状态
let screenDetails = null // 存储屏幕详情

// 初始化权限监听
const initPermission = async () => {
  permissionStatus = await navigator.permissions.query({ name: 'window-management' })
  // 监听权限变化
  permissionStatus.addEventListener('change', (e) => {
    permissionStatus = e
    updateScreens(false) // 权限变化后更新屏幕信息
  })
}

2. 屏幕信息获取与更新

通过getScreenDetails获取所有连接的显示器信息,包括分辨率、可用区域等,并监听屏幕状态变化(如新增 / 断开显示器、分辨率修改),实时更新屏幕列表:

javascript 复制代码
// 更新屏幕信息
const updateScreens = async (requestPermission = true) => {
  const screens = await getScreenDetailsWithFallback(requestPermission)
  return {
    screenList: screens,
    currentScreen: await getCurrentScreen() // 获取当前窗口所在屏幕
  }
}

// 获取屏幕详情(含兼容性兜底)
const getScreenDetailsWithFallback = async (requestPermission = false) => {
  if (!('getScreenDetails' in self)) return [window.screen]

  try {
    // 检查权限,无权限且允许申请时尝试获取
    if (!screenDetails && ((permissionStatus?.state === 'granted') || (permissionStatus?.state === 'prompt' && requestPermission))) {
      screenDetails = await window.getScreenDetails().catch(e => {
        console.error('获取屏幕信息失败', e)
        if (window.location.hostname !== 'localhost' && !window.location.protocol.includes('https')) {
          ElMessage.warning('投屏功能仅支持localhost或HTTPS环境')
        }
        return null
      })

      // 监听屏幕配置变化(如接入新显示器)
      if (screenDetails) {
        screenDetails.addEventListener('screenchange', () => {
          updateScreens(false)
          setScreenChangeListeners() // 绑定单个屏幕的变化监听
        })
        setScreenChangeListeners()
      }
    }

    // 提示单屏幕情况
    if (screenDetails?.screens.length === 1) {
      ElMessage.warning('请连接多个显示器以使用完整投屏功能')
    }

    return screenDetails?.screens || [window.screen]
  } catch (error) {
    console.error('处理屏幕信息出错', error)
    return [window.screen]
  }
}

// 绑定单个屏幕的变化监听
const setScreenChangeListeners = () => {
  const screens = screenDetails?.screens || [window.screen]
  screens.forEach(screen => {
    screen.onchange = () => updateScreens(false)
  })
}

3. 获取当前窗口所在屏幕

在多屏幕场景中,需明确当前窗口所在的显示器,避免重复打开或操作错误屏幕:

javascript 复制代码
const getCurrentScreen = async () => {
  if (!('getScreenDetails' in window)) return window.screen

  try {
    const screenDetails = await window.getScreenDetails()
    return screenDetails.currentScreen // 返回当前窗口所在屏幕
  } catch (error) {
    console.warn('获取当前屏幕信息失败', error)
    return window.screen
  }
}

三、功能实现:指定屏幕打开窗口

获取屏幕信息并确认权限后,即可在指定显示器上打开新窗口,实现投屏效果。通过window.open指定窗口位置与尺寸,确保新窗口在目标屏幕上全屏显示:

javascript 复制代码
let popup = null // 存储当前打开的窗口引用

const openPopup = async (screenIndex) => {
  const screens = await getScreenDetailsWithFallback(true)
  const currentScreen = await getCurrentScreen()

  // 检查目标屏幕是否存在
  const targetScreen = screens[screenIndex]
  if (!targetScreen) {
    ElMessage.error('无法获取指定屏幕信息,请检查环境或权限')
    return null
  }

  // 避免在当前屏幕重复打开
  if (currentScreen.label === targetScreen.label) {
    ElMessage.warning('当前屏幕已打开窗口,无需重复操作')
    return null
  }

  // 配置新窗口参数(全屏适配目标屏幕)
  const windowOptions = {
    url: window.origin, // 投屏页面地址(可替换为具体页面路径)
    x: targetScreen.availLeft || 0, // 窗口左上角x坐标(适配屏幕可用区域)
    y: targetScreen.availTop || 0, // 窗口左上角y坐标
    width: targetScreen.availWidth || 800, // 窗口宽度(屏幕可用宽度)
    height: targetScreen.availHeight || 600, // 窗口高度(屏幕可用高度)
    left: targetScreen.availLeft || 0, // 兼容部分浏览器的left参数
    top: targetScreen.availTop || 0 // 兼容部分浏览器的top参数
  }

  // 打开新窗口并存储引用
  popup = window.open(
    windowOptions.url,
    `screen-${screenIndex}`,
    `width=${windowOptions.width},height=${windowOptions.height},left=${windowOptions.left},top=${windowOptions.top}`
  )

  return popup
}

四、注意事项

  1. 环境限制:Window Management API 仅支持localhost或 HTTPS 环境,HTTP 环境下无法正常获取屏幕信息;
  2. 浏览器兼容性:目前仅 Chrome、Edge 等 Chromium 内核浏览器支持该 API, Firefox、Safari 暂不兼容;
  3. 权限管理:需用户主动授予窗口管理权限,否则无法获取多屏幕信息;
  4. 窗口监听:可添加定时器监听打开窗口的状态(如是否被关闭),避免内存泄漏或无效引用。

五、总结

Vue3 项目中的投屏功能,核心是借助 Window Management API 实现多屏幕信息的获取与窗口控制。通过权限管理、屏幕状态监听、指定窗口打开等逻辑,可实现不同显示器展示不同页面的需求。虽受限于浏览器兼容性与环境要求,但在大屏项目、多屏演示等场景中,仍能提供优质的功能体验。开发时需注意兼容性兜底与用户体验提示,确保功能稳定可用。

海云前端丨前端开发丨简历面试辅导丨求职陪跑

相关推荐
菜泡泡@1 小时前
仓库地图vue-grid-layout
前端·javascript·vue.js
u***u6853 小时前
React环境
前端·react.js·前端框架
X***E4633 小时前
前端数据分析应用
前端·数据挖掘·数据分析
4***14903 小时前
React社区
前端·react.js·前端框架
LFly_ice3 小时前
学习React-24-路由传参
前端·学习·react.js
Lhuu(重开版4 小时前
CSS:动效布局动画
前端·css
Q***K554 小时前
前端构建工具
前端
laocooon5238578864 小时前
创建了一个带悬停效果的“我的个人主页“按钮
前端
2013编程爱好者5 小时前
Vue工程结构分析
前端·javascript·vue.js·typescript·前端框架
小满zs6 小时前
Next.js第十一章(渲染基础概念)
前端