videojs v10 源代码系列解读:19 · Feature 即 Slice:播放器的能力组装机制

地图打印与 GeoTIFF 导出:框选区域、矢量标绘、一键出图 空间智能实验室 Vol.19:地图打印与 GeoTIFF 导出:框选区域、矢量标绘、一键出图 「把这块区域导成一张带地理坐标的高清图」是个很朴素的需求,但朴素不等于简单。你要在浏览器里框一个框、画几个箭头标个文字、叠一层 阅读详情

进入卷四·播放器核心。这个卷讲 @videojs/core——把 media 契约和 store 状态组合成播放器逻辑的中枢。开篇先讲 v10 最核心的组装机制:「Feature」。看完这篇你会明白,v8 的「插件」在 v10 里变成了什么。

一行代码揭开的真相

先看 packages/core/src/dom/feature.ts 的核心(L15-17):

const definePlayerSlice = defineSlice<PlayerTarget>();
// 重载 1:单参数 = plain slice 形式
export function definePlayerFeature<State>(config: SliceConfig<PlayerTarget, State>) { ... }

defineSlice<PlayerTarget>() 是什么?回忆 12 篇——它是个恒等函数,运行时零成本,纯为类型推断辅助。所以:

Feature 就是 Slice<PlayerTarget, State>,一字不差。

这不是巧合,是 v10 的核心设计决策。「播放器的一个能力」(播放、音量、字幕、全屏……)不是挂在 Player 实例上的插件对象,而是一个标准的 store slice——有 state()(返回状态+动作)和 attach()(绑定副作用)。

这意味着播放器本身就是 combine(...features) 组合出来的一个 store。04 篇追过的生命周期(createPlayer → combine → createStore → attach)里,feature 是最小单元。

PlayerTarget:feature 操作的世界

packages/core/src/dom/player.ts:23-26:

export interface PlayerTarget {
  media: Media;
  container: MediaContainer | null;
}

每个 feature 的 state() 和 attach() 都拿到这个世界:media 是 13 篇讲的 Media 能力契约对象,container 是承载播放器的 HTML 容器(可为 null——音频播放器可能没有容器)。

后面的类型都是围绕它展开的(player.ts:28-34):

export type PlayerFeature<State> = Slice<PlayerTarget, State>;
export type AnyPlayerFeature = AnySlice<PlayerTarget>;
export type PlayerStore<Features extends AnyPlayerFeature[] = []> =
  Store<PlayerTarget, UnionSliceState<Features>>;

UnionSliceState<Features> 把元组里所有 feature 的状态类型做交叉合并——所以 PlayerStore<[typeof playbackFeature, typeof volumeFeature]> 的 state 类型精确包含两者的字段,全程类型推导,不用手写。

两种 Feature 形态:plain 和 configurable

feature.ts 的精髓在它支持两种形态。

plain 形态(所有内置 feature 都用这个)

单参数调用(feature.ts:26-28):

if (arguments.length === 1) {
  return definePlayerSlice(config);   // 直接就是 slice
}

内置的 playback/volume/time 等 16 个 feature 全是这个形态——一个配置对象,完事。

configurable 形态(为外部扩展预留)

双参数调用(feature.ts:18-21):

definePlayerFeature(config, defaultConfig) // config 的 state/attach 多收一个 config 参数

看类型(feature.ts:9-13):

export interface ConfigurablePlayerFeatureConfig<Config, State>
  extends Omit<SliceConfig<PlayerTarget, State>, 'attach' | 'state'> {
  state: (ctx: StateContext<PlayerTarget>, config: Config) => State;
  attach?: (ctx: AttachContext<PlayerTarget, State>, config: Config) => void;
}

state() 和 attach() 多收一个 config 参数。实现(L30-47)通过 forConfig 闭包把 config 柯里化进去:

const forConfig = (featureConfig) => ({
  state: (ctx) => state(ctx, featureConfig),   // config 绑进 state
  attach: (ctx) => attach?.(ctx, featureConfig),
});
const defaultFeature = forConfig(defaultConfig);
// 返回的 feature 是个函数:
// 不传参 → defaultFeature
// 传参 → forConfig(featureConfig)

返回的 feature 既是个函数(可调用定制),又把 defaultFeature 的 state/attach 拷到自己身上(L43-45)——所以它既能直接当 slice 用,又能 feature({...}) 生成定制版。

最典型的使用者是 orientationLockFeature(26 篇会讲):

orientationLockFeature                    // 直接用,默认 landscape
orientationLockFeature({ type: 'portrait' })  // 定制成竖屏锁

一个是「拿来就用」,一个是「带配置的工厂」。这种「既是值又是函数」的设计在 JS 里很自然(函数是一等公民),v10 把它用在了 feature 扩展点上。

一个 Feature 长什么样:playback 回顾

拿最简单的 playback 完整看一遍(features/playback.ts:6-54):

export const playbackFeature = definePlayerFeature({
  name: 'playback',
  state: ({ target }) => ({
    paused: true, ended: false, started: false, waiting: false,
    play: () => target().media.play(),
    pause: () => {
      const media = target().media;
      if (isMediaPauseCapable(media)) media.pause();   // 谓词守卫
    },
    togglePaused: () => { /* 翻转 */ },
  }),
  attach: ({ target, signal, set }) => {
    const { media } = target;
    if (!isMediaPauseCapable(media) || !isMediaSeekCapable(media) || !isMediaSourceCapable(media)) {
      return;   // 能力守卫:不支持就静默跳过
    }
    const sync = () => set({ paused: media.paused, ended: media.ended, /* ... */ });
    sync();
    listen(media, 'play', sync, { signal });
    // ... 7 个事件
  },
});

三个组成部分清晰可见:

  1. state()——返回状态字段 + 动作方法。动作闭包通过 target()(惰性校验的 getter)访问媒体。注意 pause() 里也有谓词守卫。
  2. attach()——能力守卫 → 定义 sync() → 初始 sync → listen(事件, { signal })。
  3. signal——12 篇讲的 base 信号,detach/重 attach 自动清理。

这个「能力守卫 → sync → listen」的骨架贯穿所有 16 个 feature(21 篇逐个拆解)。

为什么这个设计比 v8 的插件好

对比 v8 的 plugin 机制,我能列出几个实质优势:

  1. 类型推导贯穿。feature 元组 → UnionSliceState → store 类型 → selector 返回类型 → UI 组件 props。全链路类型安全,拼错字段名编译期报错。

  2. 生命周期免费获得。slice 的 attach 挂在 store 的 attach 上(04 篇),signal 自动清理。v8 插件得自己管 dispose()、自己解事件。

  3. 能力降级内置。谓词守卫 + combine 的错误隔离(12 篇),feature 在不支持的媒体上自动失效,不影响其他 feature。

  4. 组合即播放器。combine(playback, volume, time) 就是一个「有播放/音量/时间的播放器」。不需要 Player 类——播放器就是 feature 的集合。这是「组合优于继承」的极致体现。

  5. 状态天然响应式。feature 的 state 就是 store state,set() 触发微任务批处理(11 篇),UI 订阅自动更新。v8 插件改状态得手动触发 UI 刷新。

小结

  • Feature = Slice<PlayerTarget, State>,恒等函数定义,零运行时成本。
  • PlayerTarget = { media, container },feature 操作的全部世界。
  • 两种形态:plain(内置 feature 全用)和 configurable(外部扩展用,可调用定制)。
  • 统一骨架:能力守卫 → sync → listen({ signal })。

下一篇看预设——v10 怎么把 16 个 feature 组装成 video/audio/live 等「开箱即用」的播放器。

机器学习第五章之决策树模型 机器学习专题系列 阅读详情

相关推荐

保姆级教程:用GATK4分析重测序数据,从fq.gz到vcf文件一步不落

本文提供了一份详细的GATK4重测序数据分析教程,涵盖从原始fq.gz文件到最终vcf文件的完整上游分析流程。通过Miniconda环境配置、数据质控、序列比对、变异检测等步骤的逐步指导,帮助生物信息学研究人员掌握标准流程,特别适合Linux命令行基础薄弱的研究者学习实践。

weixin_28366053的博客 483

videojs v10 源代码系列解读:12 · Slice 组合、选择器与取消注册表

/ L71 — 恒等函数 }// L71 — 恒等函数函数体就是——恒等函数,运行时零成本。那它图什么?纯类型推断辅助。先捕获Target,返回一个泛型<State>的工厂。// State 自动从 state 返回类型推导();// State 自动从 state 返回类型推导TypeScript 从state的返回类型推导出State,调用方不用手写状态接口,就拿到。这就是 03 篇说的「Feature 即 Slice」的代码基础——core包的本质就是。

别问我为什么代码没注释,写的时候上帝和我知道,现在只有上帝知道了。 149

带隙基准电路实战:温度补偿与流片调优全解析

带隙基准(BGR)是模拟芯片中实现高精度、低温漂电压参考的核心电路,其本质是利用硅材料禁带宽度的物理稳定性,通过PTAT(正温度系数)与CTAT(负温度系数)电压的加权叠加抵消温度影响。原理上需兼顾一阶线性补偿与二阶曲率校正,技术价值在于支撑ADC/DAC/LDO等关键模块的精度与可靠性。典型应用场景涵盖车规级MCU、工业传感器和高精度电源管理芯片。工程落地难点集中于工艺偏差、运放失调、寄生效应及版图热电耦合——这正是‘带隙基准设计’与‘带隙基准调优’的根本分野。本文聚焦真实流片经验,深入拆解Widlar架

weixin_42628280的博客 254

Web 版翻译者资料库

本项目是桌面版《翻译者资料库》的 Web 移植版,基于 Spring Boot 3.3、Thymeleaf、Bootstrap 5.3 与 MySQL 8.0 构建。它面向翻译写作提供资料、词汇、句库、文本工具、对照制作、查找、备份恢复及旧库迁移等功能,完整继承桌面版核心业务规则,支持一键启动与离线访问。

howard2005的专栏 140

基于COMSOL电弧动态仿真模型优化:高收敛性可修改吹弧方案解析

在多物理场耦合分析中,电弧动态仿真历来是数值稳定性的难点:温度从室温跃升至数万开尔文,电导率随温度呈数量级跳变,流动、传热与电磁场相互牵制,极易引发求解器不收敛或初始值不一致等问题。如何构建高收敛性的数值模型,成为开关设备灭弧性能优化的重要技术基础。通过合理的几何简化、全耦合求解器配置、辅助扫描初始化策略以及参数化建模手段,可以实现对吹弧方案的灵活调整与批量寻优,从而系统性评估气流速度、喷口形状、触头间距等关键因素对熄弧性能的影响。这类仿真方法广泛应用于断路器、接触器等高压电器产品研发,为灭弧室结构设计提供

weixin_29758911的博客 350

ORB-SLAM3代码详解 - 第 18 篇 · Atlas 多地图系统、地图保存与全系统调优

会跑:理解三线程架构与数据流(01/08/10/13),能编译、配参、复现各数据集结果。会改:掌握相机模型抽象(05)、g2o 顶点与边(14)、预积分(15),能接入新传感器、新相机、新约束。会调:理解每个参数背后的物理含义与耦合(03/15/16/18),能针对自己的平台与场景做精度/实时/鲁棒的权衡。ORB-SLAM3 的价值不止于一个可用的 SLAM 系统,更在于它是一套工程化的几何状态估计模板:清晰的模块边界、可替换的相机/传感器抽象、紧耦合优化的标准范式。

PX4-SLAM-PNC 172

Jackson 序列化 / 反序列化注解 完整版笔记

Jackson 序列化 / 反序列化注解 完整版笔记

handsome_sai的博客 272

010、Zephyr RTOS开发环境搭建(Docker)

摘要 本文分享了使用Docker搭建Zephyr RTOS开发环境的实践经验。作者通过团队新人配置环境的真实案例,指出传统安装方式存在版本冲突、缓存污染等问题,而Docker方案能确保环境一致性。文章详细介绍了自定义Docker镜像的设计思路,重点解决工具链版本匹配、Python虚拟环境隔离等问题,将镜像体积从2GB优化到800MB。提供了从拉取镜像到点亮LED的完整工作流程,并总结了USB设备直通、文件权限、缓存问题等常见陷阱。还探讨了多阶段构建、CI集成等进阶用法,同时客观分析了Docker方案的局限性

m0_50546716的博客 79

【项目推荐】基于 SpringBoot3 + Spring AI 的游泳馆管理系统:Agent + RAG + Function Calling 一次学全

它不是玩具 Demo,而是一个「业务 + AI」双主线交织的真实系统——预约业务在跑,AI 客服在旁边实时查库作答,两条线通过 Function Calling、RAG、站内消息串成一体。面试官问「你做过什么 AI 项目」时,你能从业务场景讲到架构取舍,从 RAG 切分参数讲到降级兜底——这和「我调了一下 ChatGPT 的 API」是完全不同的两个段位。项目已包含完整的建表 SQL、初始化数据、部署文档,克隆下来就能跑。获取方式:见文末说明 / 后台回复关键词获取。—— 完 ——

深耕开发,专注编程实战。分享源码解析、项目搭建、问题排查笔记,沉淀技术,持续更新。 347

Mathematica 训练课(12)常用注释方法

Mathematica从入门到进阶

qq_25018077的博客 9075

Android系统解决-授予管理所有文件的权限问题

Android版本一直在加,Android9/Android10/Android11/Android12/Android13/Android14/Android15 , 客户app 也在不断适配,但是存在特别是定制产品中,客户不愿意适配,啥问题都让系统解决,绕过一定机制、实现。这里说的就是一个常见的常见需求:Android13 上面,客户要求默认授予管理所有文件的权限,如下:问题是机器重启后这个权限仍需要重新打开才行,那就是每次开机使用某些功能前都需要授权一次。是的ADB对应命令。

十年饮冰,难凉热血 2539

MCP 协议会成为前端 AI 工程的标准接口吗?

MCP(Model Context Protocol)正在成为连接 AI 模型与外部工具、数据源的一层通用协议。本文从 MCP 的核心机制出发,分析它在浏览器与前端工程中的落地边界,讨论它能否成为前端 AI 工程的标准接口,并给出当下更务实的架构选择建议。

m0_62937412的博客 336

SA8155P QCOM 车载系统介绍

高通车载相机开发

qq_37057338的博客 5229

LangGraph 本地 build 频频翻车,最终在服务器跑通流式对话

先说结论:我本地那个,一次都没成功过。三次,三次,全挂在拉镜像上。而顺得像刚上过油。这就很像我高中那辆自行车:骑着能走,一上锁就坏。那天晚上我盯着终端里那行红字看了很久,想的不是技术方案,想的是——为什么同一个工具,可以一边让我觉得自己很行,一边让我觉得自己不太行。

人工智能AI技术 97

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

海外平台频繁弹验证?从 DNS、WebRTC 到浏览器指纹的环境异常排查清单

在运营多地区海外平台账号时,即使代理节点通畅、TCP 握手成功,仍可能遇到频繁人机验证、地区限制、播放失败等异常。核心结论是:这类问题往往不在网络传输层,而在浏览器环境参数与网络出口之间的逻辑自洽性。本文从 DNS 泄漏、WebRTC 穿透、时区与语言匹配、Canvas/WebGL 指纹、TLS 特征五个维度,给出一份可复现的环境异常排查清单,并对比个人手动配置与工程化环境管理方案的适用边界。适用于跨境运营、多账号运维团队。

P1Browser【p1指纹浏览器】的博客 183

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

智能问诊的流程

本文介绍基于FastAPI构建的医疗多Agent系统MediAgent,通过症状分析、诊断推理与治疗建议等模块协同,实现从问诊到报告生成的完整工作流。系统采用前后端分离架构,结合MySQL、RabbitMQ与Docker实现工程化部署,支持异步化验结果接入。虽当前状态暂存于内存,但已具备可扩展性,未来可通过Redis持久化、消息队列联动及医疗安全机制完善,应用于慢病管理、辅助决策等场景,推动AI在医疗流程中的落地应用。

Joey 的工作空间~ 773

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

信号链电路怎么选运放?奥特四款信号链运放解析【选型参考】

在模拟电路设计中,运放作为信号链的“第一道门槛”,其微小误差往往决定了整个系统的成败。

naNa_1120的博客 191

流式输出 SSE:实现 AI 对话打字机效果后端开发

摘要解决传统 HTTP 请求在 LLM 长文本生成时导致的客户端长时间阻塞与 TTFT 极高的问题。适用于需为 AI 应用提供打字机效果、优化交互体验的后端开发工程师。读完可获得基于 FastAPI 与 SSE(Server-Sent Events)技术的流式响应实现代码、协议规范及生产环境避坑指南。关键词SSE、流式输出、FastAPI、打字机效果、TTFT、大模型推理背景与问题大模型(LLM)生成完整回复通常耗时数秒至数十秒,传统请求-响应模型导致用户界面长时间无响应,体验极差。

2402_85729970的博客 181

基于 YOLOv8 的森林火灾检测系统(Web 版)

本项目面向林区早期火情识别场景,使用YOLOv8完成火焰(Fire)与烟雾(Smoke)两类目标的检测模型训练,并以FastAPI构建 Web 检测平台,把模型能力封装为可直接登录使用的系统。平台除常规的图片、批量、视频、摄像头检测外,还提供同图多权重对比、数据集浏览与标注核对、模型热切换,以及把训练搬到网页上的能力:可在浏览器配置超参数发起真实训练,训练中在线调整学习率、查看进度与动态曲线,训练完成后下载产物或直接应用到检测。

Michael_Jay的博客 62

身份验证漏洞专题(三):持久登录、密码重置与密码修改中的凭据绑定缺陷

密码登录与双因素认证是身份验证的主干流程,但一个完整的认证体系还依赖三类辅助机制:持久登录("记住我")、密码重置、密码修改。这三类机制的共同特征是:它们同样携带或验证凭据,同样直接决定认证状态的归属,但实现时获得的防护强度往往远低于登录页面本身。攻击者绕不开登录接口时,常常可以从这些辅助入口进入。

2401_85321170的博客 630

二进制木马免杀-Python 分离免杀与 Web 挂马

二进制木马免杀-Python 分离免杀与 Web 挂马

2503_94637398的博客 268

Vue 前端开发 AI 对话页面:流式消息渲染、文件上传

关键点是不能手动设置 Content-Type 为 multipart/form-data,必须由浏览器自动生成带有 boundary 的请求头,否则后端无法解析。思路:将对象序列化为 JSON 字符串,作为 FormData 的一个普通字段(如 formData.append(‘payload’, JSON.stringify(data))),后端接收该字段后再反序列化。若上传大文件(>10MB),需实现独立的分片上传接口,在提交对话前先获取文件 id 或 url,再随文本发送引用。移除输入框的禁用态;

2402_85729970的博客 388

在Open-WebUI中提升向量化速度

让Open-WebUI AI聊天的向量化过程不超过10秒,而不是默认的20+分钟……

xyzzklk的博客 574

Writeup 4 0xGame 2021 · command (WEB)

前端限制不可信:永远不要相信前端的任何限制(如disabled按钮、JS 验证等)。攻击者可以直接构造 HTTP 数据包绕过前端校验,所有的安全限制必须在后端实现。命令执行/注入(RCE):Web 应用如果直接调用系统命令且未对输入进行严格过滤,攻击者可以利用;||等符号拼接恶意命令。绕过技巧:在 CTF 中,如果遇到命令执行被过滤,常见的绕过方式包括:${IFS}$IFS$9等。。cat /fla?或cat /fl*。Linux 基础。

hengdonghui的博客 131

使用HTML+CSS+JavaScript实现文件上传弹窗

使用HTML+CSS+JavaScript实现文件上传弹窗

bjzhang75的博客 207

ArkWeb 混合开发的内存清理与桥接陷阱

起初我以为是 H5 内部的定时器没有清理,结果接了 DevEco Studio 的 Profiler 一看,全是 ArkTS 侧的原生对象没有释放。改用 RESIZE 后,键盘弹出只会压缩窗口高度,底部的输入框会自适应滚动到可视区域,页面顶部的元素则岿然不动。综上所述,混合开发绝不是简单的拼接,管好桥接的生命周期,做好跨域兜底,才是稳定运行的前提。如果不去主动干预,它会把你的原生内存吃得连骨头都不剩。在 H5 的输入框打字时,软键盘一弹出来,整个 Web 页面就被顶得飞起,连顶部的原生导航栏都不见了。

2502_91284977的博客 235
上一篇: videojs v10 源代码系列解读:18 · 媒体轨道与 rendition 列表实现
下一篇: videojs v10 源代码系列解读:20 · Feature 预设:video/audio/live/background
逻辑玩家
博客等级 码龄19年 75粉丝 108原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值