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
}
四、注意事项
- 环境限制:Window Management API 仅支持localhost或 HTTPS 环境,HTTP 环境下无法正常获取屏幕信息;
- 浏览器兼容性:目前仅 Chrome、Edge 等 Chromium 内核浏览器支持该 API, Firefox、Safari 暂不兼容;
- 权限管理:需用户主动授予窗口管理权限,否则无法获取多屏幕信息;
- 窗口监听:可添加定时器监听打开窗口的状态(如是否被关闭),避免内存泄漏或无效引用。
五、总结
Vue3 项目中的投屏功能,核心是借助 Window Management API 实现多屏幕信息的获取与窗口控制。通过权限管理、屏幕状态监听、指定窗口打开等逻辑,可实现不同显示器展示不同页面的需求。虽受限于浏览器兼容性与环境要求,但在大屏项目、多屏演示等场景中,仍能提供优质的功能体验。开发时需注意兼容性兜底与用户体验提示,确保功能稳定可用。
海云前端丨前端开发丨简历面试辅导丨求职陪跑