HarmonyOS 6实战:Web组件与Navigation返回协调

news2026/4/1 3:23:33
还在为Web页面和原生页面返回逻辑打架而头疼你的HarmonyOS应用如何让H5页面的“上一页”和Navigation的“返回”和谐共处为什么用户点击返回按钮时有时退回网页历史有时却直接退出整个页面哈喽大家好我是你们的老朋友爱学习的小齐哥哥。前段时间我在开发一款混合应用时需要在Navigation框架中嵌入WebView展示H5内容。用户反馈了一个让人困惑的问题“为什么在H5页面里浏览了几个商品详情后点击返回键不是退回上一个商品而是直接退出了整个页面” 我尝试了各种拦截方案要么返回逻辑混乱要么侧滑手势失效直到我深入研究了WebviewController的导航控制和Navigation的生命周期协调机制。今天我将带你彻底解决这个“返回逻辑混乱”的难题从问题现象到核心原理再到完整的实战方案。这套基于onBackPressed回调的智能返回协调方案已经在我们多个混合应用中稳定运行确保了用户操作的一致性和可预测性。目录一、为什么需要关注Web组件在Navigation中的返回协调在深入技术细节前我们先明确混合导航场景的特殊性。与纯原生或纯H5应用相比Navigation中嵌入Web组件的返回逻辑带来了独特的挑战对比维度纯原生应用纯H5应用Navigation嵌套Web组件返回栈管理​Navigation页面栈Web历史栈双重栈管理页面栈历史栈返回键处理​统一由Navigation处理浏览器控制需要协调两者优先级侧滑手势​Navigation默认支持浏览器默认支持手势冲突需解决用户体验​一致但功能受限一致但体验割裂功能强大但逻辑复杂开发复杂度​简单简单复杂需处理边界情况核心矛盾在于Navigation管理着原生页面的跳转栈而Web组件内部维护着自己的浏览历史栈。当用户触发返回操作时系统需要智能决定应该让Web退回上一个网页还是让Navigation退回上一个原生页面。二、整体设计理解双重返回栈的协调机制Web组件在Navigation中的返回协调不是简单的“事件拦截”而是一个需要精心设计的优先级决策系统。理解其工作流程是解决问题的关键ststart: 用户触发返回操作 op1operation: 触发onBackPressed回调 cond1condition: Web是否有历史记录? op2operation: 执行Web.backward() op3operation: 执行Navigation.pop() cond2condition: 是否处理成功? e1end: Web退回上一页 e2end: Navigation退回上一页 e3end: 执行默认返回 st-op1-cond1 cond1(yes)-op2-cond2 cond1(no)-op3-cond2 cond2(yes)-e1 cond2(no, right)-e3关键组件解析onBackPressed回调Navigation提供的返回按钮事件拦截器是决策的“总开关”。accessBackward()方法WebviewController的方法检查Web组件是否有可后退的历史记录。backward()方法WebviewController的方法让Web组件后退到上一个网页。pop()方法NavPathStack的方法让Navigation退出当前页面。WebviewController对象Web组件的控制核心管理网页的加载、导航和历史。协调决策流程事件捕获用户点击返回按钮或侧滑触发onBackPressed回调。状态检查通过accessBackward()检查Web组件内部是否有历史记录。优先级决策如果Web有历史优先让Web后退否则让Navigation后退。执行操作调用对应的backward()或pop()方法。结果返回通过返回值告诉系统是否已处理该事件。三、解决方案智能返回协调策略3.1 场景一共用返回按钮的基础方案根据链接1的内容最基础的解决方案是让Web组件和Navigation共用同一个返回按钮import { webview } from kit.ArkWeb; import { BusinessError } from kit.BasicServicesKit; Builder export function PageOneBuilder() { PageOne(); } Component export struct PageOne { pageInfos: NavPathStack new NavPathStack(); controller: webview.WebviewController new webview.WebviewController(); build() { NavDestination() { Column() { // 嵌入Web组件 Web({ src: https://www.example.com/h5-page, controller: this.controller }) .width(100%) .height(100%); } .width(100%) .height(100%); } .title(H5内容页) .onBackPressed(() { // 核心决策逻辑 if (this.controller.accessBackward()) { // Web有历史记录优先退回上一个网页 this.controller.backward(); return true; // 已处理阻止默认行为 } else { // Web无历史记录退回Navigation上一个页面 return false; // 未处理执行默认返回 } }) .onReady((context: NavDestinationContext) { // 获取页面栈信息 this.pageInfos context.pathStack; }); } }关键点onBackPressed回调返回true表示已处理返回事件系统不再执行默认返回返回false表示未处理系统会执行Navigation的默认返回逻辑通过accessBackward()检查Web内部历史栈状态使用backward()让Web组件后退到上一网页3.2 场景二增强的侧滑返回处理链接1还提供了更完整的示例包含异常处理和更精细的控制import { webview } from kit.ArkWeb; import { BusinessError } from kit.BasicServicesKit; Builder export function BackPressBuilder() { BackPress(); } Component export struct BackPress { pageInfos: NavPathStack new NavPathStack(); private controller: webview.WebviewController new webview.WebviewController(); build() { NavDestination() { Column() { Web({ src: https://www.example.com/h5-page, controller: this.controller, }); }; } .title(BackPress) .height(100%) .width(100%) .onBackPressed(() { try { // 判断Web是否可以返回 const canGoBack this.controller.accessBackward(); if (canGoBack) { // 可以返回执行Web后退 this.controller.backward(); return true; // 已处理 } // 不可返回交给Navigation处理 return false; } catch (error) { // 异常处理 const bizError error as BusinessError; console.error(返回操作异常: ErrorCode: ${bizError.code}, Message: ${bizError.message}); return false; // 异常时交给系统默认处理 } }); } }增强特性添加了try-catch异常处理提高健壮性详细的错误日志记录便于调试异常时降级到系统默认处理避免崩溃代码结构更清晰易于维护3.3 进阶方案多层级返回栈协调在实际复杂应用中可能需要更精细的控制策略class SmartBackHandler { private static instance: SmartBackHandler; private webHistoryStack: Mapstring, number new Map(); // 记录各Web页面历史深度 private currentPageId: string ; static getInstance(): SmartBackHandler { if (!SmartBackHandler.instance) { SmartBackHandler.instance new SmartBackHandler(); } return SmartBackHandler.instance; } /** * 注册Web页面 */ registerWebPage(pageId: string, controller: webview.WebviewController): void { this.currentPageId pageId; this.webHistoryStack.set(pageId, 1); // 初始深度为1 // 监听Web导航变化 controller.onNavigationStateChange((event) { this.updateHistoryDepth(pageId, event.canGoBack); }); } /** * 智能处理返回事件 */ handleBackPress(controller: webview.WebviewController): boolean { try { const currentDepth this.webHistoryStack.get(this.currentPageId) || 1; if (currentDepth 1) { // Web有深层历史优先返回 controller.backward(); this.webHistoryStack.set(this.currentPageId, currentDepth - 1); console.info(Web返回: 深度 ${currentDepth} - ${currentDepth - 1}); return true; } else if (controller.accessBackward()) { // Web有历史但深度为1返回后应退出页面 controller.backward(); console.info(Web返回最后一页下次将退出页面); return true; } else { // Web无历史退出Navigation页面 console.info(Web无历史退出Navigation页面); return false; } } catch (error) { console.error(智能返回处理失败:, error); return false; } } /** * 更新Web历史深度 */ private updateHistoryDepth(pageId: string, canGoBack: boolean): void { if (canGoBack) { const currentDepth this.webHistoryStack.get(pageId) || 1; this.webHistoryStack.set(pageId, currentDepth 1); } else { this.webHistoryStack.set(pageId, 1); } } /** * 页面销毁时清理 */ unregisterWebPage(pageId: string): void { this.webHistoryStack.delete(pageId); if (this.currentPageId pageId) { this.currentPageId ; } } } // 在组件中使用 Component struct EnhancedWebPage { private controller: webview.WebviewController new webview.WebviewController(); private backHandler SmartBackHandler.getInstance(); State pageId: string webpage_${Date.now()}; aboutToAppear(): void { // 注册页面 this.backHandler.registerWebPage(this.pageId, this.controller); } aboutToDisappear(): void { // 清理注册 this.backHandler.unregisterWebPage(this.pageId); } build() { NavDestination() { Web({ src: https://www.example.com, controller: this.controller }) } .onBackPressed(() { return this.backHandler.handleBackPress(this.controller); }); } }3.4 生产级方案完整的返回协调系统对于企业级应用需要更完整的解决方案// 返回协调配置 interface BackPressConfig { enableWebFirst: boolean; // Web优先 enableSwipeBack: boolean; // 启用侧滑返回 doublePressExit: boolean; // 双击退出 exitConfirmMessage?: string; // 退出确认提示 maxWebHistoryDepth: number; // 最大Web历史深度 } // 生产级返回协调器 class ProductionBackCoordinator { private config: BackPressConfig { enableWebFirst: true, enableSwipeBack: true, doublePressExit: false, maxWebHistoryDepth: 10 }; private lastBackTime: number 0; private webHistory: Array{url: string, timestamp: number} []; /** * 处理返回事件主入口 */ async handleBackPress( controller: webview.WebviewController, navPathStack?: NavPathStack ): Promiseboolean { // 1. 检查双击退出 if (this.config.doublePressExit this.isDoublePress()) { return this.handleDoublePressExit(); } // 2. 检查Web历史 if (this.config.enableWebFirst controller.accessBackward()) { const handled await this.handleWebBackward(controller); if (handled) { return true; } } // 3. 检查Navigation返回 if (navPathStack) { return this.handleNavigationBack(navPathStack); } // 4. 默认处理 return false; } /** * 处理Web返回 */ private async handleWebBackward(controller: webview.WebviewController): Promiseboolean { try { // 检查当前页面是否需要拦截返回 const shouldIntercept await this.shouldInterceptWebBack(controller); if (shouldIntercept) { return true; // 已拦截不执行实际返回 } // 执行Web返回 controller.backward(); // 记录返回历史 this.recordWebBackHistory(); return true; } catch (error) { console.error(Web返回失败:, error); return false; } } /** * 处理Navigation返回 */ private handleNavigationBack(navPathStack: NavPathStack): boolean { // 检查是否需要确认 if (this.config.exitConfirmMessage this.shouldShowExitConfirm()) { this.showExitConfirmDialog(); return true; // 已处理显示确认框 } // 执行Navigation返回 navPathStack.pop(); return true; } /** * 检查是否为双击 */ private isDoublePress(): boolean { const now Date.now(); const isDouble (now - this.lastBackTime) 500; // 500ms内 this.lastBackTime now; return isDouble; } /** * 处理双击退出 */ private handleDoublePressExit(): boolean { // 显示退出提示 prompt.showToast({ message: 再按一次退出应用, duration: 1000 }); return true; } /** * 检查是否需要拦截Web返回 */ private async shouldInterceptWebBack(controller: webview.WebviewController): Promiseboolean { // 这里可以实现业务逻辑例如 // 1. 检查表单是否已保存 // 2. 检查支付流程是否完成 // 3. 显示自定义确认对话框 // 示例检查当前页面是否有未保存的表单 const hasUnsavedChanges await this.checkUnsavedChanges(controller); if (hasUnsavedChanges) { const result await this.showUnsavedChangesDialog(); return !result; // 用户取消则拦截返回 } return false; } /** * 显示未保存更改对话框 */ private async showUnsavedChangesDialog(): Promiseboolean { return new Promise((resolve) { // 实际开发中显示自定义对话框 // 这里简化为直接返回true resolve(true); }); } /** * 记录Web返回历史 */ private recordWebBackHistory(): void { this.webHistory.push({ url: back, timestamp: Date.now() }); // 限制历史记录长度 if (this.webHistory.length this.config.maxWebHistoryDepth) { this.webHistory.shift(); } } /** * 检查未保存更改 */ private async checkUnsavedChanges(controller: webview.WebviewController): Promiseboolean { // 实际开发中可能需要与H5页面通信 // 这里简化为固定返回 return false; } /** * 检查是否需要显示退出确认 */ private shouldShowExitConfirm(): boolean { // 例如在首页或特定页面显示确认 return true; } /** * 显示退出确认对话框 */ private showExitConfirmDialog(): void { prompt.showDialog({ title: 确认退出, message: this.config.exitConfirmMessage || 确定要退出吗, buttons: [ { text: 取消, color: #666666 }, { text: 确定, color: #007DFF } ] }).then(result { if (result.index 1) { // 用户确认退出 // 实际开发中可能需要执行退出逻辑 console.info(用户确认退出应用); } }); } } // 在组件中集成 Component struct ProductionWebPage { private controller: webview.WebviewController new webview.WebviewController(); private coordinator new ProductionBackCoordinator(); private pageInfos: NavPathStack new NavPathStack(); build() { NavDestination() { Column() { Web({ src: https://www.example.com/app, controller: this.controller }) .width(100%) .height(100%) // 自定义返回按钮可选 Button(返回) .onClick(() this.handleBackPress()) .margin(20) } } .onBackPressed(() { return this.handleBackPress(); }) .onReady((context: NavDestinationContext) { this.pageInfos context.pathStack; }); } private async handleBackPress(): Promiseboolean { return await this.coordinator.handleBackPress(this.controller, this.pageInfos); } }四、常见问题与解答Q1onBackPressed返回true和false有什么区别A这是控制返回行为的关键返回true表示已处理返回事件系统不会执行默认的返回操作返回false表示未处理返回事件系统会执行默认的返回操作Navigation退出当前页面.onBackPressed(() { if (this.controller.accessBackward()) { this.controller.backward(); return true; // 我们自己处理了系统别管了 } return false; // 我们没处理系统你按默认方式来吧 })Q2如何同时支持物理返回键和侧滑返回AonBackPressed回调会同时响应导航栏返回按钮点击物理返回键Android设备侧滑返回手势如果启用无需额外处理但需要注意侧滑手势可能与Web内容滚动冲突。Q3Web页面内的JavaScript能控制返回行为吗A可以通过Web与原生通信// ArkTS侧 this.controller.onInterceptRequest((event) { if (event.request.url harmonyos://back/intercept) { // 拦截返回执行自定义逻辑 this.showConfirmDialog(); return true; // 拦截请求 } return false; }); // JavaScript侧 window.harmonyosBack { requestGoBack: function() { // 发送自定义协议请求 location.href harmonyos://back/intercept; } }; // 在需要拦截返回时调用 // harmonyosBack.requestGoBack();Q4如何记录用户的返回路径用于分析A可以在返回处理器中添加埋点private recordBackAction(source: web | nav, depth: number): void { hiAppEvent.write({ domain: user_behavior, name: back_action, params: { back_source: source, web_history_depth: depth, page_name: this.getCurrentPageName(), timestamp: Date.now() } }); } // 在handleBackPress中调用 if (canGoBack) { this.recordBackAction(web, currentDepth); controller.backward(); } else { this.recordBackAction(nav, 0); return false; }Q5多个Web组件之间如何共享返回状态A通过全局状态管理class GlobalBackState { private static instance: GlobalBackState; private webStates: Mapstring, WebState new Map(); static getInstance(): GlobalBackState { if (!GlobalBackState.instance) { GlobalBackState.instance new GlobalBackState(); } return GlobalBackState.instance; } setWebState(pageId: string, canGoBack: boolean, historyCount: number): void { this.webStates.set(pageId, { canGoBack, historyCount }); } getWebState(pageId: string): WebState | undefined { return this.webStates.get(pageId); } } // 在Web组件中 aboutToAppear(): void { // 监听Web导航状态 this.controller.onNavigationStateChange((event) { GlobalBackState.getInstance().setWebState( this.pageId, event.canGoBack, event.historyCount || 0 ); }); }五、总结Web组件在Navigation中的返回协调是HarmonyOS混合开发中的关键体验优化点特别适合需要嵌入H5内容的复杂应用场景。通过本文的分析你应该已经掌握了✅问题根因理解Navigation页面栈和Web历史栈的双重管理冲突✅核心机制掌握onBackPressed回调的拦截和控制原理✅基础方案使用accessBackward()和backward()实现智能返回✅进阶方案实现多层级历史管理和异常处理✅生产实践构建完整的返回协调系统支持埋点和用户行为分析核心要点总结拦截点onBackPressed是控制返回行为的总入口决策依据accessBackward()检查Web是否有历史记录执行动作backward()让Web后退pop()让Navigation后退返回值true表示已处理false表示交还系统处理异常处理添加try-catch确保健壮性最佳实践建议始终优先检查Web历史提供符合用户预期的返回体验为返回操作添加适当的埋点分析用户行为考虑添加退出确认防止误操作导致数据丢失在复杂场景中使用状态管理协调多个Web组件的返回逻辑定期测试返回功能确保在各种边界情况下都能正常工作记住流畅的返回体验不仅是技术实现更是对用户操作习惯的深度理解和尊重。现在就去优化你的混合应用返回逻辑让用户在原生和H5间无缝穿梭吧如果有更多问题或有趣的实现场景欢迎在评论区交流讨论

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2427915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…