Electron + Vue3开源跨平台壁纸工具实战(十)渲染进程

107 阅读6分钟

fbw_social_preview.png

系列

Electron + Vue3开源跨平台壁纸工具实战(一)

Electron + Vue3开源跨平台壁纸工具实战(二)本地运行

Electron + Vue3开源跨平台壁纸工具实战(三)主进程

Electron + Vue3开源跨平台壁纸工具实战(四)主进程-数据管理(1)

Electron + Vue3开源跨平台壁纸工具实战(五)主进程-数据管理(2)

Electron + Vue3开源跨平台壁纸工具实战(六)子进程服务

Electron + Vue3开源跨平台壁纸工具实战(七)进程通信

Electron + Vue3开源跨平台壁纸工具实战(八)主进程-核心功能

Electron + Vue3开源跨平台壁纸工具实战(九)子进程服务(2)

Electron + Vue3开源跨平台壁纸工具实战(十)渲染进程

源码

省流点我进Github获取源码,欢迎fork、star、PR

渲染进程

渲染进程负责用户界面展示和交互,采用 Vue 3 + Element Plus 技术栈,包含多个独立窗口,每个窗口都有特定的功能和用途。


主窗口 (MainWindow)

主窗口是应用的核心界面,采用侧边栏 + 主内容区的布局设计,支持多页面切换和功能模块管理。

1. 窗口布局

  • 侧边栏:可折叠的菜单导航,支持展开/收起切换
  • 主内容区:动态加载不同功能页面,支持页面切换动画
  • 自定义标题栏:支持窗口拖拽、最小化、最大化、关闭等操作

关键代码片段:

<el-container class="window-container">
  <el-aside class="window-side-wrapper" :width="settingData.expandSideMenu ? '70px' : '0'">
    <SideMenu v-if="settingData.expandSideMenu" />
    <div class="side-expand-btn" @click="toggleExpandSideMenu">
      <IconifyIcon :icon="settingData.expandSideMenu ? 'ep:caret-left' : 'ep:caret-right'" />
    </div>
  </el-aside>
  <el-main class="window-main-wrapper">
    <MainContainer />
  </el-main>
</el-container>

2. 功能页面

  • Explore:探索页面,浏览和发现壁纸
  • Search:搜索页面,关键词搜索壁纸
  • Favorites:收藏页面,管理收藏的壁纸
  • History:历史页面,查看浏览历史
  • Words:词库页面,管理搜索关键词
  • Setting:设置页面,应用配置管理
  • Utils:工具页面,实用功能集合
  • About:关于页面,应用信息展示

关键代码片段:

const componentDict = {
  Explore,
  Search,
  Favorites,
  History,
  Words,
  Setting,
  Utils,
  About
}

3. 菜单管理

  • 支持菜单启用/禁用配置
  • 动态过滤显示启用的菜单项
  • 支持主进程页面跳转事件监听
  • 集成二维码生成功能(H5 服务地址)

关键代码片段:

const enabledMenus = computed(() => {
  const list = menuList.value.filter((item) => item.placement.includes('sideMenu'))
  if (!settingData.value?.enabledMenus?.length) {
    return list
  }
  return list.filter((item) => {
    if (item.canBeEnabled) {
      return settingData.value.enabledMenus.includes(item.name)
    }
    return true
  })
})

悬浮球 (SuspensionBall)

悬浮球提供快捷操作功能,支持拖拽移动和点击操作,是壁纸切换的快速入口。

1. 拖拽功能

  • 支持鼠标拖拽移动窗口位置
  • 拖拽阈值检测,区分点击和拖拽操作
  • 实时更新窗口位置到主进程

关键代码片段:

const onMouseMove = (e) => {
  if (!startPos.value || !windowStartPos.value) return

  const deltaX = e.screenX - startPos.value.x
  const deltaY = e.screenY - startPos.value.y
  const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)

  if (distance > moveThreshold || isDragging.value) {
    isDragging.value = true
    const newX = windowStartPos.value.x + deltaX
    const newY = windowStartPos.value.y + deltaY
    window.FBW.setWindowPosition('suspensionBall', { x: newX, y: newY })
  }
}

2. 快捷操作

  • 切换主窗口:点击悬浮球切换主窗口显示/隐藏
  • 自动切换壁纸:启动/停止自动壁纸切换功能
  • 设置同步:监听主进程设置数据更新

关键代码片段:

const onMouseUp = () => {
  if (!isDragging.value) {
    // 如果没有拖拽,则认为是点击事件
    window.FBW.toggleMainWindow()
  }
}

const onToolClick = async (funcName) => {
  if (typeof window.FBW[funcName] === 'function') {
    await window.FBW[funcName]()
  }
}

预览图片窗口 (ViewImageWindow)

预览图片窗口提供独立的图片查看功能,支持图片列表浏览和单张图片查看。

1. 窗口功能

  • 独立窗口显示,支持窗口大小调整
  • 自定义标题栏,支持窗口操作
  • 图片查看组件集成

关键代码片段:

<template>
  <div class="window-container">
    <custom-title-bar :resize-window="true" window-name="viewImageWindow" />
    <div class="window-container-inner">
      <view-image ref="viewImageRef" :options="viewImageOptions" />
    </div>
  </div>
</template>

2. 数据通信

  • 监听主进程发送的图片数据
  • 支持图片列表和当前索引传递
  • 实时更新显示内容

关键代码片段:

const doView = (activeIndex = -1, list = []) => {
  viewImageRef.value.view(activeIndex, list)
}

const onSendPostDataCallback = (event, data) => {
  doView(data.activeIndex, data.list)
}

onBeforeMount(() => {
  window.FBW.onSendPostData(onSendPostDataCallback)
})

动态壁纸窗口 (DynamicWallpaperWindow)

动态壁纸窗口用于播放视频作为桌面壁纸,支持多种视频控制功能。

1. 视频播放

  • 支持本地视频文件播放
  • 自动转换为 fbwtp:// 协议 URL
  • 支持 HTTP 和 HTTPS 视频源

关键代码片段:

const handleSetVideoSource = (event, source) => {
  if (source) {
    if (!source.startsWith('fbwtp://') && !source.startsWith('http')) {
      const formattedPath = source.replace(/\\/g, '/')
      videoSrc.value = `fbwtp://fbw/api/videos/get?filePath=${formattedPath}`
    } else {
      videoSrc.value = source
    }
  }
}

2. 视频控制

  • 静音控制:支持视频静音/取消静音
  • 帧率控制:限制视频播放帧率,优化性能
  • 缩放模式:支持 cover、contain 等缩放模式
  • 亮度/对比度:实时调整视频显示效果

关键代码片段:

const controlFrameRate = (timestamp) => {
  if (!videoRef.value) return

  const frameInterval = 1000 / frameRate.value

  if (timestamp - lastFrameTime >= frameInterval) {
    if (videoRef.value.paused) {
      videoRef.value.play()
    }
    lastFrameTime = timestamp
  } else {
    if (!videoRef.value.paused) {
      videoRef.value.pause()
    }
  }

  rafId = requestAnimationFrame(controlFrameRate)
}

3. 视觉效果

  • 支持亮度、对比度滤镜调整
  • 实时计算和应用 CSS 滤镜效果
  • 响应式布局适配

关键代码片段:

const filterStyle = computed(() => {
  return `brightness(${brightness.value / 100}) contrast(${contrast.value / 100})`
})

律动壁纸窗口 (RhythmWallpaperWindow)

律动壁纸窗口基于音频频谱数据渲染动态视觉效果,支持多种律动效果。

1. 音频采集

  • 使用 Web Audio API 采集音频数据
  • 自动检测虚拟声卡设备(VB-Audio、BlackHole、立体声混音)
  • 支持音频频谱分析和数据提取

关键代码片段:

const init = async () => {
  audioContext = new (window.AudioContext || window.webkitAudioContext)()
  const devices = await navigator.mediaDevices.enumerateDevices()
  const audioInputs = devices.filter((d) => d.kind === 'audioinput')

  const virtualDevice = audioInputs.find(
    (d) =>
      d.label.includes('VB-Audio') ||
      d.label.includes('BlackHole') ||
      d.label.includes('立体声混音') ||
      d.label.toLowerCase().includes('stereo mix')
  )

  if (virtualDevice) {
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: { deviceId: virtualDevice.deviceId }
    })
    source = audioContext.createMediaStreamSource(stream)
    analyser = audioContext.createAnalyser()
    analyser.fftSize = 1024
    dataArray = new Uint8Array(analyser.frequencyBinCount)
    source.connect(analyser)
    runEffect()
  }
}

2. 律动效果

支持 20 种不同的律动效果:

  • 基础效果:BarEffect、WaveEffect、BallEffect
  • 频谱效果:SpectrumRingEffect、SpectrumFlowerEffect、Bars3DEffect
  • 粒子效果:ParticleFountainEffect、FireworkEffect、MusicNoteRainEffect
  • 动画效果:DiscoEffect、RainbowEffect、WindmillEffect、TaijiEffect
  • 流体效果:LiquidRippleEffect、FlowingLinesEffect
  • 特殊效果:BreathingHaloEffect、DynamicGridEffect、RotatingStarburstEffect、MuyuEffect

关键代码片段:

function runEffect() {
  if (!leafer) return

  if (effectInstance) {
    effectInstance.destroy()
  }

  const effectName =
    config.value.effect.charAt(0).toUpperCase() + config.value.effect.slice(1) + 'Effect'
  const EffectClass = Effects[effectName]

  if (EffectClass) {
    effectInstance = new EffectClass(leafer, toRaw(config.value))
    draw()
  }
}

3. 渲染引擎

  • 使用 Leafer UI 作为渲染引擎
  • 支持实时音频数据渲染
  • 可配置的效果参数:尺寸比例、颜色、动画、密度、位置、采样范围

关键代码片段:

function draw() {
  if (!analyser || !effectInstance) return

  analyser.getByteFrequencyData(dataArray)
  const [start, end] = config.value.sampleRange
  const startIndex = Math.floor((start * dataArray.length) / 100)
  const endIndex = Math.floor((end * dataArray.length) / 100)

  effectInstance.render(dataArray.slice(startIndex, endIndex))
  animationId = requestAnimationFrame(draw)
}

4. 效果基类

所有律动效果都继承自 BaseEffect 基类,提供:

  • 位置计算:支持 9 个位置(top-left、top、top-right、right、bottom-right、bottom、bottom-left、left、center)
  • 尺寸管理:基于窗口尺寸和比例计算效果区域
  • 数据降维:支持 max、min、average 三种数据聚合方式
  • 颜色映射:支持线性渐变和径向渐变填充
  • 调试功能:可选的调试边框显示

关键代码片段:

export class BaseEffect {
  constructor(leafer, config) {
    this.leafer = leafer
    this.config = config
    this.debugRect = null
    this.bodySize = this.getBodySize()
    this.renderDebug()
  }

  getPosition(width, height, bodyWidth, bodyHeight, margin = 0) {
    switch (this.config.position) {
      case 'top-left':
        return { x: margin + bodyWidth / 2, y: margin + bodyHeight / 2 }
      case 'center':
      default:
        return { x: width / 2, y: height / 2 }
      // ... 其他位置
    }
  }
}

技术特点

1. 状态管理

  • 使用 Pinia 进行状态管理
  • 支持多窗口间的数据同步
  • 与主进程 IPC 通信保持数据一致性

2. 组件化设计

  • 高度模块化的组件结构
  • 可复用的自定义组件(如 CustomTitleBar、ViewImage)
  • 统一的组件注册和导入机制

3. 响应式布局

  • 基于 Element Plus 的响应式布局
  • 支持窗口大小调整和内容自适应
  • 流畅的过渡动画效果

4. 国际化支持

  • 集成 i18n 国际化框架
  • 支持多语言界面切换
  • 统一的文本管理机制