videojs v10 源代码系列解读:26 · presentation 子系统:全屏/PiP/远程播放/方向锁

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

卷四收官篇。presentation 子系统(core/src/dom/presentation/)处理「播放器的呈现形态」——全屏、画中画、远程播放、屏幕方向锁。这是浏览器兼容的重灾区:iOS Safari 的 webkit 前缀、Safari PWA 的 PiP 陷阱、方向锁的异步竞态。这篇看 v10 怎么把这些坑一个个填平。

架构:纯函数库 + feature 装配

先说一个我读源码时的发现:presentation/ 下的文件(fullscreen.ts、pip.ts 等)是纯函数库,没有任何事件监听。事件监听在 store feature 层(store/features/fullscreen.ts 等)。

这个分离很清晰:

  • presentation/*.ts——无状态的浏览器兼容封装(「怎么请求全屏」「怎么判断在不在全屏」)。
  • store/features/*.ts——feature 装配(「什么时候同步状态到 store」「绑什么事件」)。

另外 presentation/index.ts(3 行)只导出 fullscreen/pip/remote-playback——orientation 不在桶文件里,仅由 orientation-lock feature 直接路径导入(因为它不是「能力」而是「配置型 feature」)。

fullscreen:三级降级 + 四层判定

请求全屏的三级降级(presentation/fullscreen.ts:54-79)

// L57-66:container 存在且 document 支持全屏
el.requestFullscreen()      // L60-62 — 标准
el.webkitRequestFullscreen() // L64-66 — webkit 前缀
// L69-72:都不行 →
video.webkitSetPresentationMode('fullscreen')  // iOS presentationMode 兜底
// L75-78:最后 →
video.requestFullscreen()   // 媒体自定义(如 Cast 场景的 host 提供)

标准 → webkit 前缀 → iOS presentationMode → 媒体自定义。四级路径覆盖所有浏览器。

退出全屏的顺序刻意相反(exitFullscreen,L81-102):webkit 的 presentationMode 先退(L84-88),再标准 doc.exitFullscreen()(L90-92)。为什么?因为 iOS 的 presentation mode 是独立状态,得先解除它标准 API 才能生效。

判断「在不在全屏」的四层判定(isFullscreen,L29-52)

// 1. L30-33 — iOS presentationMode
video.webkitPresentationMode === 'fullscreen'
// 2. L35-38 — 标准/webkit 的 fullscreenElement 比对
fullscreenElement === container || fullscreenElement === media
// 3. L44-46 — :fullscreen 伪类(matchesFullscreen 内部 try/catch,L20-27)
container.matches(':fullscreen') || media.matches(':fullscreen')
// 4. L50-51 — 非标准 video.isFullscreen(由 video host 设置)

第 3 层的注释(L40-43)解释了为什么需要它::fullscreen 伪类匹配全屏元素及其祖先(跨 shadow boundary)——覆盖「内层 <video> 通过原生控件进全屏」的情况(此时 fullscreenElement 是内层元素,但 container 是它的祖先)。

第 4 层的 video.isFullscreen 是非标准属性——由 media host(15 篇)设置,覆盖 Cast 这种「概念上的全屏」(接收端全屏,本地 document 无感知)。

能力探测的动态探针(isFullscreenEnabled,L5-13)

doc.fullscreenEnabled || doc.webkitFullscreenEnabled 都假时,动态创建一个 <video> 探针(L11),检测 isFunction(video.webkitSetPresentationMode)(L12)——iOS Safari 的旧路径。这和 21 篇 volume 的 canSetVolume 是同一套「运行时探针」手法。

feature 装配(store/features/fullscreen.ts:44-66)

attach({ target, signal, set }) {
  set({ fullscreenAvailability: isFullscreenEnabled() ? 'available' : 'unsupported' });  // L47-49
  const sync = () => set({ fullscreen: isFullscreen(container, media) });  // L51-54
  sync();                                                  // L56
  listen(document, 'fullscreenchange', sync, { signal });          // L58
  listen(document, 'webkitfullscreenchange', sync, { signal });    // L59
  if ('webkitPresentationMode' in video) {                          // L62-65 — iOS 补充
    listen(media, 'webkitpresentationmodechanged', sync, { signal });
  }
}

同时绑标准和非标准事件,iOS 再补一个。还有一个贴心细节(L16-19):requestFullscreen 先退 PiP——注释写着 “browser behavior is inconsistent”(有些浏览器全屏时会打断 PiP,主动退更可控)。

pip:Safari PWA 陷阱

presentation/pip.ts 的请求/退出逻辑和 fullscreen 对称(webkit 优先/回退),最有意思的是能力探测(L5-14):

export function isPictureInPictureEnabled(): boolean {
  if (document.pictureInPictureEnabled) {
    // Safari PWA 排除:UA 匹配 Safari 且 display-mode: standalone 时禁用
    if (/.*Version\/.*Safari\/.*/.test(navigator.userAgent)
        && matchMedia('(display-mode: standalone)').matches) {
      return false;   // L7-9
    }
    return true;
  }
  // webkit 探针回退 L12-13
}

Safari 的 PWA(standalone 模式)里 PiP 会崩——pictureInPictureEnabled 说支持,实际用就炸。v10 用 UA + display-mode: standalone 双重判定提前排除。这种坑不可能从规范推出来,只能是实踩后写进代码的。

feature 装配(store/features/pip.ts:49-71)监听 enterpictureinpicture/leavepictureinpicture(L63-64)+ iOS 的 webkitpresentationmodechanged(L67-70)。togglePictureInPicture 同样先退 fullscreen(L34-46)——PiP 和全屏互斥。

remote-playback:鸭子类型 + 浏览器 UI

presentation/remote-playback.ts(27 行)最短:

// L4-10 — 鸭子类型检测
export function resolveRemote(media) {
  if (isObject(media.remote) && 'state' in media.remote && 'prompt' in media.remote) {
    return media.remote;   // cast 成 MediaRemotePlaybackCapability['remote']
  }
  return null;
}
// L20-26 — 请求远程播放
export function requestRemotePlayback(media) {
  const remote = resolveRemote(media);
  if (!remote) throw new DOMException('Remote playback not supported', 'NotSupportedError');  // L23
  remote.prompt();   // L25 — AirPlay/Cast 的设备选择 UI 由浏览器弹出
}

注意 L25——remote.prompt() 触发的是浏览器原生的设备选择 UI(AirPlay/Cast 菜单)。v10 不自己画设备列表。17 篇讲的 GoogleCast 组件提供了 RemotePlayback 的规范实现(google-cast/remote-playback.ts),这里消费的正是那个接口。

orientation:异步竞态的优雅解法

presentation/orientation.ts(77 行)是我觉得这份源码里「小而美」的典范。问题:screen.orientation.lock() 是 async 的——await 期间用户可能已经调了 unlock()。怎么防止「迟到的 lock 覆盖已生效的 unlock」?

解法是两个标志分离「事实」和「意图」(L30-31):

let locked = false;    // 事实:lock 真正成功
let desired = false;   // 意图:调用方想要锁

lock() 的完整流程(L45-65):

async lock() {
  desired = true;                          // 先记意图
  // ... lock 非函数直接 return(L52,不支持时静默)
  try {
    await orientation.lock(type);          // L55 — 异步等真正锁上
    if (desired) locked = true;            // L58 — await 期间意图还在,才置事实
    else releaseOrientation();             // L60-64 — 意图已变,立刻释放!
  } catch { /* L56-58 */ }
}
unlock() {
  desired = false;                         // L67 — 只改意图
  if (locked) { releaseOrientation(); locked = false; }  // L68-70
}

L58 的 if (desired) 是竞态的裁决点:await 回来时如果 desired 已经是 false(unlock 抢先了),立刻调 releaseOrientation() 反向补偿——迟到的 lock 被立即撤销。这个「意图标志 + 完成后校验」的模式,比 Promise 链或状态机都轻。

orientation-lock feature:configurable 实战

store/features/orientation-lock.ts(53 行)是 19 篇讲的 configurable feature 的内置使用者:

// L16-52 — 可配置 feature,默认 { type: 'landscape' }(L51)
orientationLockFeature({ type: 'portrait' })   // 这样定制

它的 attach(L21-49)做边沿检测:wasFullscreen 标志(L25、L35)记住上一次全屏态,进入全屏 lock()(L29-30)、退出 unlock()(L31-32)——方向锁跟随全屏状态自动开关(全屏看视频锁横屏,退出解锁)。同样监听三种 fullscreenchange(L40-46),abort 兜底 unlock(L48)。

小结

presentation 子系统是「浏览器兼容教科书」,带走这些手法:

  1. 纯函数库 + feature 装配分离——兼容封装无状态,监听在 feature。
  2. 多级降级链——fullscreen 四级请求路径,退出顺序刻意相反。
  3. 四层全屏判定——presentationMode/fullscreenElement/:fullscreen 伪类/非标准属性,覆盖 shadow DOM 和 Cast。
  4. 运行时探针——动态 <video> 探测 iOS 能力(和 volume 的 canSetVolume 同款)。
  5. Safari PWA 陷阱——UA + display-mode 双判。
  6. 意图/事实双标志解异步竞态——orientation 的 desired/locked。
  7. 互斥主动处理——全屏先退 PiP、PiP 先退全屏(“browser behavior is inconsistent”)。

至此卷四讲完。播放器核心的全貌:feature 组装(19-21)、无头 Core(22-23)、选择器(24)、输入桥(25)、presentation(26)。下一篇进入卷五——SPF 流处理框架,全系列的重头戏,15 篇。

嵌入式设备电量显示实战:MCP3421 ADC采集从原理到代码全解析(附避坑指南) 本文详细解析了嵌入式设备中MCP3421 ADC芯片在电量显示应用中的硬件设计、寄存器配置、I2C通信调试及低功耗优化策略。通过实战代码和避坑指南,帮助开发者实现高精度电量监测,特别针对I2C时序和分压电路设计等常见问题提供解决方案,适用于物联网终端和移动设备开发。 阅读详情

相关推荐

MuJoCo 机械臂关节空间阻抗控制Impedance实现(附代码)

阻抗控制通过调整关节的刚度和阻尼,让机器人在接触时产生顺应性,减少冲击力,其核心目标是在接触外部载荷时能够自适应调整输出力矩,实现力与位置的协同控制。阻抗控制可以很快的到达设定位置,在此基础上,使用mujoco交互中的施加外力操作,可以看到当外力松开后,机械臂也可以很快的回弹回设定位置。其中self.Kp和self.Kd为固定刚度和阻尼系数,通过修改刚度和阻尼参数,可以变得更柔顺来应对各种场景。注释掉该行后,直接simulate仿真可以看到机械臂控制位置震荡等情况,接下来引入关节空间阻抗控制的代码。

darcsdn 1274

Web 版翻译者资料库

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

howard2005的专栏 140

FOFA奇技淫巧:从搜索语法到实战场景的深度挖掘

本文深入探讨了FOFA搜索语法在网络空间测绘中的高效应用,从基础语法到实战场景的深度挖掘。通过渗透测试、威胁狩猎、资产发现等实际案例,展示了如何利用FOFA精准定位目标系统、识别蜜罐、追踪威胁,并提供了合规使用指南和性能优化技巧,助力安全工作者提升效率。

weixin_32428571的博客 236

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

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

handsome_sai的博客 272

Pywinauto与Inspect.exe完美搭配:解决Windows应用UI自动化中的元素定位难题

本文详细介绍了如何将Pywinauto与Inspect.exe结合,以解决Windows应用UI自动化中的核心难题——元素定位。通过实战指南,阐述了如何利用Inspect.exe在UIA模式下精准侦察控件属性,并将这些信息转化为Pywinauto的稳健定位策略,从而高效自动化WPF、WinForms等现代框架构建的复杂桌面应用。

weixin_29297127的博客 520

以太网以及车载以太网概述

千兆网线和百兆网线区别 1、所谓的百兆网线其实就是 五类线 和超五类线 ,而千兆网线主要是指六类线 和超六类线 ,另外还有古老的十兆网线也就是指 四类线 和 三类线 等。 2、在使用上,其实千兆网线和百兆网线是没什么区别的,千兆网线完全兼容百兆网络。 3、百兆网线的线芯是8芯,但上传和下载只用到了其中的4根,而千兆网线需要完全用到8根。 4、另外在线芯的排布上,千兆网线的线芯中间有个十字形的塑料架,用来把四组8芯的线分开,这个百兆网线是没有的, 5、所有的网线在外皮上都有种类标识,CAT5 CAT

$好记性还是要多记录$ 4074

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

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

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

基于Python的虚拟货币社区情绪分析与市场价格预测爬虫实现

本文探讨了如何利用Python爬虫技术获取虚拟货币社区数据,并通过情感分析预测市场价格走势。我们将使用最新的异步爬虫框架、自然语言处理技术和机器学习模型,构建一个完整的社区情绪分析系统。本文提供了详细的代码实现和理论解释,适合作为毕业设计参考。关键词:Python爬虫、虚拟货币、情感分析、价格预测、异步爬虫、机器学习爬虫框架aiohttp和httpx用于异步HTTP请求HTML解析和parsel数据存储MongoDB和Pandas用于数据处理自然语言处理库和VADER情感分析工具机器学习和。

2201_76125261的博客 521

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

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

m0_62937412的博客 336

uniapp [安卓苹果App端] - 详细实现手机蓝牙连接打印机及打印票据小票/标签/面单/热敏小票订单/快递单等通用兼容适配解决方案,Uniapp对接蓝牙打印机支持各种主流品牌及打印指令,强悍插件

uni-app,安卓Android,苹果ios,安卓app端,苹果App端,uniapp苹果app,蓝牙打印机,uniappAPP实现通过蓝牙连接打印机打印,uniapp蓝牙连接打印机,安卓蓝牙打印插件,蓝牙打印机,蓝牙ble低功率及高功率打印机小票、标签、面单打印,手机PDA蓝牙打印插件,连接蓝牙打印机,蓝牙连接,打印文本、图片、条码、二维码,兼容斑马打印机、佳博打印机,TSC打印机,免费蓝牙打印机组件,蓝牙打印条码,蓝牙打印机连接,热敏蓝牙打印机,便携式打印机,打印机搜索不到,连接失败,发送打印命令

🏆 前端领域优质创作者 1万+

Python爬虫实战:爬取ETF基金持仓变化

在python复制编辑本文详细介绍了如何使用Python的Scrapy框架爬取ETF基金的持仓变化信息,包括项目的搭建、数据的提取与存储、以及数据的可视化分析。通过本项目,读者可以掌握基本的网页爬虫技术,并应用于实际的财经数据采集与分析中。

2201_76125261的博客 629

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

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

人工智能AI技术 97

ABAP CDS 视图参数 parameter_list 详解与最佳实践:从语法、作用域到可运行范例

本文系统梳理了ABAP CDS视图的WITH PARAMETERS定义与使用。主要内容包括:1)参数声明语法及其在整条SELECT语句中的贯穿使用;2)参数在WHERE/HAVING/ON等位置的多种写法(:pname和$parameters.pname);3)参数在航空公司航线筛选等实际业务场景中的应用;4)参数与会话变量的协作策略;5)在JOIN ON、HAVING、CASE等高级用法中的实践;6)提供完整的CDS视图与ABAP程序示例,展示参数声明、使用及Open SQL传参方式。所有内容均基于SAP

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 372

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

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

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

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

智能问诊的流程

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

Joey 的工作空间~ 773

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

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

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

naNa_1120的博客 191

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

流式输出 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

热工测点布线改造难题?IDCB 远程 I/O 采集前端简化现场布线

IDCB智能数据采集前端基于Modbus-RTU协议,支持热电偶、热电阻、直流信号多类型混采,单设备多通道接入,减少模块选型压力。双总线冗余设计保障数据连续性,适配锅炉、窑炉等高可靠性工况。采用总线式布线替代点对点接线,大幅减少电缆用量,配合组态软件或LCD面板,实现远程监控与现场调试便捷化。适用于脱硫脱硝、就地监控及系统改造项目,具备抗干扰、隔离保护、掉电存参等特性,有效提升热工测点采集系统的稳定性与运维效率。

wxyzzdh200988的博客 192
上一篇: videojs v10 源代码系列解读: 25 · 输入动作注册表:手势/热键→媒体的桥
下一篇: videojs v10 源代码系列解读:27 · SPF 总览:三层模型与设计目标
逻辑玩家
博客等级 码龄19年 75粉丝 108原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值