Bilibili-Evolved v1 风格设置面板样式组件解析:从样式覆盖到实现原理
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
Bilibili-Evolved(哔哩哔哩增强脚本)在向 v2 架构演进的过程中,将设置面板重新设计为圆角卡片与弹出式布局。v1-panel组件的作用,是通过一组全局 SCSS 覆盖规则,让设置面板恢复 v1 时代「全屏停靠、无圆角、侧边栏悬浮」的经典外观。本文将围绕该组件的元数据定义与样式实现,结合设置面板、停靠(dock)等源码,逐段拆解其覆盖逻辑、方向适配机制与动画细节,帮助读者理解样式类组件在脚本内的注册方式与写法。
组件概览:一个纯样式组件
v1-panel在组件目录registry/lib/components/style/v1-panel/下仅由三个文件组成:
index.md:组件说明文档,内容为「使用 v1 风格的设置面板样式」;index.ts:组件元数据定义,负责向脚本注册该组件;v1-panel.scss:核心样式实现,约 80 行,全部为对设置面板样式的覆盖规则。
从目录归属看,它位于registry/lib/components/style/(样式类组件)分类下,与dark-mode、scrollbar、player-shadow等样式组件并列,属于「通过注入 CSS 改变界面外观」的一类功能,不包含任何业务逻辑或entry运行时代码。
组件元数据:instantStyles 注入机制
组件的注册入口是 index.ts,全文如下:
import { defineComponentMetadata } from '@/components/define' export const component = defineComponentMetadata({ name: 'v1PanelStyle', displayName: 'v1 风格设置面板', tags: [componentsTags.style], entry: none, instantStyles: [ { name: 'v1PanelStyle', style: () => import('./v1-panel.scss'), }, ], })关键点逐项说明:
name: 'v1PanelStyle':组件在脚本内部的唯一标识,也是样式注册名与设置项键名的基础;displayName: 'v1 风格设置面板':设置面板(功能列表)中向用户展示的名称,同时也是搜索匹配的文本来源之一(见下文 SettingsPanel 的搜索逻辑);tags: [componentsTags.style]:将组件归入「样式」标签分组,便于在设置面板中按标签筛选;entry: none:组件没有运行时代码,entry为空,说明它纯粹靠样式生效;instantStyles:声明「即时样式」列表。与按需加载的组件样式不同,instantStyles会在组件启用后立刻注入页面,style: () => import('./v1-panel.scss')采用动态import惰性加载 SCSS 内容,编译后由脚本的样式管理模块负责挂载到文档。
这种「元数据声明 + 惰性加载样式」的写法是 Bilibili-Evolved 样式类组件的标准范式,同类组件(如registry/lib/components/style/scrollbar/index.ts、registry/lib/components/style/player-shadow/index.ts)均遵循同一结构,读者可横向对照。
样式实现逐段拆解
v1-panel.scss的全部规则都挂在.be-settings容器类下。.be-settings正是设置面板入口组件SettingsContainer.vue的根节点类名(见 SettingsContainer.vue),它承载了左侧悬浮的「功能 / 设置」两个圆形图标按钮,以及两个弹出面板(widgets-panel-popup与settings-panel-popup)。
1. 弹窗面板:贴边全屏化
.be-settings { > .be-popup { top: 0 !important; left: 0 !important; body.settings-panel-dock-right & { left: unset !important; right: 0 !important; } transform: translateZ(0) translateY(0) translateX(calc(-101% * var(--direction))) !important; --panel-height: 100vh !important; &.open { transform: translateZ(0) translateY(0) translateX(0) !important; } ...- 默认情况下将弹出面板固定到视口左上角(
top: 0; left: 0),并把--panel-height强制设为100vh,即面板高度撑满整个视口——这是 v1 时代「设置页全屏覆盖」的核心观感; - 关闭状态下,面板沿
--direction方向平移-101%,恰好完全移出屏幕外侧;translateZ(0)用于强制创建独立渲染层,避免位移过程中出现锯齿或闪烁; - 当停靠在右侧(
body.settings-panel-dock-right)时,left复位、right: 0,面板改从右边缘贴齐。
其中--direction是停靠方向变量:停靠左侧时为1,停靠右侧时为-1(见 src/components/settings-panel/dock/_left.scss 与 src/components/settings-panel/dock/_right.scss)。所有calc(... * var(--direction))的位移都以此实现「同一套规则、左右镜像」的效果。
> * { border-radius: 0 !important; border-width: 0 1px 0 0 !important; height: var(--panel-height) !important; body.settings-panel-dock-right & { border-width: 0 0 0 1px !important; } }- 面板内部子元素(即
.settings-panel与.widgets-panel)的圆角被清零,边框改为仅保留贴边一侧的 1px 分隔线(左侧停靠保留右边框,右侧停靠保留左边框),高度同步撑满视口; - 逐条覆盖均带
!important,这是样式组件的必然选择——需要压过脚本自身 SCSS(如SettingsPanel.vue中默认的border-radius: 8px)以及页面既有样式。
2. 侧边栏:悬浮胶囊与旋转动画
> .sidebar > * { width: 52px !important; border-radius: 21px !important; transform: translateX(calc(-13px * var(--direction))) !important; display: flex !important; justify-content: flex-end !important; body.settings-panel-dock-right & { justify-content: flex-start !important; } .be-icon { transition: 0.2s ease-out !important; } &:hover { transform: translateX(calc(8px * var(--direction))) !important; .be-icon { transform: rotate(360deg) !important; } } &.open { transform: translateX(calc(12px * var(--direction))) !important; } }.sidebar即SettingsContainer.vue中承载「功能 / 设置」两个图标的悬浮条。v1 风格将其从默认的圆形小按钮(默认尺寸26px、圆形背景,见 SettingsContainer.vue)改造成:
- 拉长为胶囊:宽度固定
52px、圆角21px,图标通过display: flex加justify-content: flex-end靠外侧对齐; - 默认半隐藏:整体向屏幕外平移
-13px,只露出约一半,符合 v1 时代侧边栏「贴边收纳」的交互习惯; - 悬停滑出:鼠标悬停时平移到
+8px露出全貌,同时内部图标rotate(360deg)转满一圈,过渡动画0.2s ease-out; - 激活态:面板打开(
.open)时侧边栏滑到+12px的位置并保持。
3. 组件标签:收尾圆角修正
.settings-panel-popup .component-tags .component-tags-item:last-child { border-radius: 0 !important; }设置面板左侧的标签栏(ComponentTags.vue渲染的.component-tags)在 v1 全屏贴边的形态下,最后一个标签项的圆角被清零,与全屏无圆角的面板观感保持一致,避免出现「面板直角、标签圆角」的割裂感。
4. 功能面板(widgets-panel):单列流式布局
.widgets-panel { padding: 24px !important; @include no-scrollbar(); &-header { margin-bottom: 36px !important; } .widgets-popup { --columns: 1; --medal-columns: 1; --title-columns: 1; left: 50%; top: calc(100% + 4px) !important; transform-origin: top !important; box-sizing: border-box; max-width: calc(100% + 44px) !important; max-height: unset !important; transform: translateX(calc(-50% * var(--direction))) scale(0.9) !important; display: flex !important; flex-wrap: wrap !important; > * { flex-grow: 1; } &.open { transform: translateX(calc(-50% * var(--direction))) scale(1) !important; } body.settings-panel-dock-right & { left: unset !important; right: 50% !important; } } }功能面板(WidgetsPanel.vue)承载着「已启用功能」的开关列表,v1 样式对它的调整包括:
- 面板内边距加大到
24px,隐藏滚动条(@include no-scrollbar(),该 mixin 定义于脚本共享样式); - 强制各列数为
1(--columns: 1等),功能项改为单列纵向排布; .widgets-popup(功能项分组弹出菜单)以left: 50%水平居中、出现在面板头部下方,未展开时scale(0.9)轻微缩小、展开时恢复scale(1),形成「自上而下放大浮现」的入场动效;- 停靠右侧时对称切换为
right: 50%定位。
与设置面板源码的联动机制
方向变量从何而来
--direction并非由v1-panel.scss定义,而是由停靠样式在body层面维护。设置面板组件在 src/components/settings-panel/index.ts 中监听「设置面板停靠」选项:
addComponentListener( `${metadata.name}.dockSide`, (value: SettingsPanelDockSide) => { document.body.classList.toggle( 'settings-panel-dock-right', value === SettingsPanelDockSide.Right, ) }, true, )停靠侧由SettingsPanelDockSide枚举(dock.ts)定义,取值为Left = '左侧'/Right = '右侧'。当选择右侧停靠时,body获得settings-panel-dock-right类,同时 dock/_right.scss 在.be-settings上设置--direction: -1;左侧停靠则由 dock/_left.scss 设置--direction: 1。v1-panel.scss中的大量calc(... * var(--direction))正是依赖这层「方向变量」实现了左右镜像的同一套布局,这也解释了为什么样式中会出现大量body.settings-panel-dock-right &嵌套选择器来兜底边界情况。
全屏高度与默认高度的差异
脚本默认的面板高度是--panel-height: calc(100vh - 120px)(见 SettingsContainer.vue),弹出面板垂直居中显示、带 8px 圆角(见 SettingsPanel.vue)。v1-panel.scss正是针对这三点(高度、定位、圆角)逐一覆盖,把它拉回 v1 的全屏贴边形态。因此可以推断:该组件的覆盖目标是 v2 重构后的设置面板 DOM 结构,若未来面板 DOM 结构变化,组件也需要同步适配。
组件启停与样式注入
作为「即时样式」组件,v1PanelStyle启用后由脚本的样式管理模块立即注入v1-panel.scss编译产物,关闭后随即移除,无需刷新页面即可在 v1/v2 两套视觉间切换。该组件与「设置面板停靠」选项相互独立:v1 样式在左、右两种停靠下均能正常工作(通过--direction与settings-panel-dock-right类的组合适配)。
在设置面板中定位与搜索
启用后,用户可在脚本设置面板中通过「样式」标签(tags: [componentsTags.style])筛选到「v1 风格设置面板」这一项。设置面板的搜索逻辑(见 SettingsPanel.vue)会将组件的name、displayName、标签名称与描述文本拼合后做小写匹配,因此搜索「v1」「面板」等关键词即可命中本组件。此外,ComponentTags.vue渲染的标签栏就是上文样式中被修正圆角的.component-tags区域。
小结
v1-panel是 Bilibili-Evolved 中一个典型的「纯样式覆盖型」组件:通过defineComponentMetadata声明元数据、以instantStyles惰性注入 SCSS,用约 80 行带!important的覆盖规则,将 v2 圆角弹出式设置面板还原为 v1 时代的全屏贴边外观。其实现中利用--direction方向变量与settings-panel-dock-right类实现左右停靠的镜像适配,并通过translateX(calc(... * var(--direction)))配合translateZ(0)完成滑入滑出与旋转动画,为读者理解脚本内样式组件的注册方式、覆盖策略与停靠联动机制提供了完整可参考的范例。若需调整 v1 面板的贴边方向、胶囊宽度或动画时长,直接修改 v1-panel.scss 中的对应规则即可。
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考