零基础学 ArkUI24手把手教你开发一个简易浏览器 App博主说手机浏览器是我们每天打开最多次的应用之一。你有没有想过——在 HarmonyOS 上实现一个简易浏览器其实只需要几十行代码ArkUI 内置了强大的Web 组件可以轻松加载网页、执行 JavaScript、处理页面加载事件。今天我们就用 Web 组件做一款支持导航栏、前进后退、加载进度、书签管理的简易浏览器。 应用场景在 App 内嵌网页查看内容、快速访问常用网站、开发 Hybrid 应用时调试前端页面……简易浏览器的应用场景非常广泛。我们要开发的浏览器会实现地址栏输入 URL 并加载加载进度条前进 / 后退 / 刷新网页标题显示书签管理收藏常用网站加载状态提示加载中 / 加载失败全屏模式扩展⚙️ 运行环境要求项目版本要求操作系统Windows 10/11、macOS 13 或 Ubuntu 22.04DevEco Studio5.0.3.800 及以上HarmonyOS SDKAPI 12HarmonyOS 5.0.0及以上应用模型Stage 模型开发语言ArkTS核心组件Webohos.web.webview️ 实战从零搭建简易浏览器Step 1认识 ArkUI 的 Web 组件Web组件是 ArkUI 内置的网页渲染引擎基于 Chromium 内核importwebviewfromohos.web.webview;// 在 build 中使用 Web 组件Web({src:https://www.example.com,controller:this.controller}).width(100%).height(100%).javaScriptAccess(true)// 允许 JS.domStorageAccess(true)// 允许 DOM 存储.onPageBegin((url){/* 开始加载 */}).onPageEnd((url){/* 加载完成 */}).onErrorReceive((err){/* 加载出错 */})Step 2浏览器数据结构设计// 书签数据结构interfaceBookmark{id:string;title:string;url:string;icon:string;// favicon}// WebView 控制器controller:webview.WebviewControllernewwebview.WebviewController();// 浏览历史用于前进/后退判断StatecanGoBack:booleanfalse;StatecanGoForward:booleanfalse;Step 3完整代码// pages/Index.ets — 简易浏览器主页面importwebviewfromohos.web.webview;interfaceBookmark{id:string;title:string;url:string;}EntryComponentstruct SimpleBrowser{// 状态变量 StateurlInput:stringhttps://www.example.com;StatepageTitle:string;StateisLoading:booleanfalse;StateloadProgress:number0;StatecanGoBack:booleanfalse;StatecanGoForward:booleanfalse;StateshowBookmarks:booleanfalse;Statebookmarks:Bookmark[][{id:1,title:HarmonyOS 开发文档,url:https://developer.harmonyos.com},{id:2,title:华为开发者社区,url:https://developer.huawei.com},{id:3,title:CSDN,url:https://www.csdn.net},];privatecontroller:webview.WebviewControllernewwebview.WebviewController();privatewebviewRef:stringwebview;// 页面生命周期 aboutToAppear(){// 默认加载首页this.loadUrl(this.urlInput);}// 加载 URL loadUrl(url:string){if(!url.startsWith(http://)!url.startsWith(https://)){urlhttps://url;}this.urlInputurl;this.isLoadingtrue;this.loadProgress0;this.controller.loadUrl(url);}// 导航控制 goBack(){if(this.controller.accessBackward()){this.controller.backward();}}goForward(){if(this.controller.accessForward()){this.controller.forward();}}refresh(){this.controller.refresh();}// 添加书签 addBookmark(){constnewBookmark:Bookmark{id:Date.now().toString(),title:this.pageTitle||this.urlInput,url:this.urlInput};// 去重constexiststhis.bookmarks.find(bb.urlnewBookmark.url);if(!exists){this.bookmarks.push(newBookmark);}}// 删除书签 deleteBookmark(bm:Bookmark){constidxthis.bookmarks.indexOf(bm);if(idx-1)this.bookmarks.splice(idx,1);}// UI 构建 build(){Column(){// ---- 地址栏 导航按钮 ----Row(){Button().fontSize(20).backgroundColor(transparent).fontColor(this.canGoBack?#007AFF:#ccc).enabled(this.canGoBack).onClick((){this.goBack();})Button().fontSize(20).backgroundColor(transparent).fontColor(this.canGoForward?#007AFF:#ccc).enabled(this.canGoForward).onClick((){this.goForward();})TextInput({placeholder:输入网址...,text:this.urlInput}).layoutWeight(1).height(36).backgroundColor(#F0F0F0).borderRadius(18).padding({left:12}).onSubmit((val:string){this.loadUrl(val);})Button(↻).fontSize(18).backgroundColor(transparent).fontColor(#007AFF).onClick((){this.refresh();})Button().fontSize(16).backgroundColor(transparent).onClick((){this.addBookmark();})}.width(100%).padding({top:8,bottom:4,left:8,right:8}).backgroundColor(#F8F8F8)// ---- 加载进度条 ----if(this.isLoading){Progress({value:this.loadProgress,total:100,type:ProgressType.Linear}).width(100%).height(3).color(#007AFF).value(this.loadProgress)}// ---- 书签收藏栏 ----if(this.showBookmarks){Column(){Row(){Text( 书签).fontSize(16).fontWeight(FontWeight.Bold)Button(✕).fontSize(14).backgroundColor(transparent).fontColor(#999).onClick((){this.showBookmarksfalse;})}.width(100%).justifyContent(FlexAlign.SpaceBetween)List(){ForEach(this.bookmarks,(bm:Bookmark){ListItem(){Row(){Text().fontSize(20)Column(){Text(bm.title).fontSize(14).fontWeight(FontWeight.Bold)Text(bm.url).fontSize(11).fontColor(#999).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1)}.layoutWeight(1).margin({left:8})Button(✕).fontSize(12).backgroundColor(transparent).fontColor(#FF3B30).onClick((){this.deleteBookmark(bm);})}.padding(10).width(100%)}.onClick((){this.loadUrl(bm.url);this.showBookmarksfalse;})},(bm:Bookmark)bm.id)}.height(200)}.width(100%).backgroundColor(#fff).shadow({radius:4,color:#20000000,offsetY:2})}// ---- 网页内容区域 ----Web({src:this.urlInput,controller:this.controller}).width(100%).layoutWeight(1).javaScriptAccess(true).domStorageAccess(true).onPageBegin((){this.isLoadingtrue;this.loadProgress0;}).onPageEnd((event){this.isLoadingfalse;this.loadProgress100;this.pageTitlethis.controller.title();// 更新前进/后退状态this.canGoBackthis.controller.accessBackward();this.canGoForwardthis.controller.accessForward();}).onProgressChange((event){this.loadProgressevent.newProgress;}).onErrorReceive((event){this.isLoadingfalse;console.error(页面加载失败:,event.request.getRequestUrl());}).onTitleReceive((event){this.pageTitleevent.title;})// ---- 底部状态栏 ----Row(){if(this.isLoading){Text(加载中...).fontSize(12).fontColor(#007AFF)}else{Text(this.pageTitle||this.urlInput).fontSize(12).fontColor(#999).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1)}Text().fontSize(14).onClick((){this.showBookmarks!this.showBookmarks;})}.width(100%).padding({left:16,right:16,top:6,bottom:6}).backgroundColor(#F0F0F0).justifyContent(FlexAlign.SpaceBetween)}.width(100%).height(100%).backgroundColor(#FFFFFF)}} 核心知识点深度解析1. Web 组件的核心属性属性作用示例javascriptAccess(true)启用 JS 执行网页功能正常domStorageAccess(true)启用 localStorage记住登录状态onPageBegin开始加载回调显示加载动画onPageEnd加载完成回调隐藏加载动画onProgressChange进度变化回调更新进度条onErrorReceive加载错误回调错误提示2. WebviewController 控制方法controller.loadUrl(url)// 加载 URLcontroller.backward()// 后退controller.forward()// 前进controller.refresh()// 刷新controller.title()// 获取页面标题controller.accessBackward()// 能否后退controller.accessForward()// 能否前进3. 浏览器状态机用户输入 URL → loadUrl() → 开始加载isLoadingtrue ↓ onProgressChange → 更新进度条 ↓ onPageEnd → 标题更新 前进/后退状态更新 ↓ 加载完成isLoadingfalse⚠️ 避坑指南坑原因正确做法网页白屏忘了javascriptAccess(true)或domStorageAccess(true)必须开启这两个属性URL 加载失败用户输入了 “baidu.com” 不带协议自动补全https://前进/后退按钮无效没调用accessBackward()判断页面加载完后更新状态进度条不更新没监听onProgressChange绑定 onProgressChange 事件书签数据丢失只存在内存中用preferences持久化页面标题为空页面还没触发 onTitleReceive降级使用 URL 作为标题 最佳实践URL 自动补全用户输入不带http(s)://时自动补全减少输入错误加载进度条用 Linear Progress 给用户视觉反馈提升体验前进/后退状态灰化不能前进时按钮用灰色#ccc并enabled(false)书签去重添加前检查 URL 是否已存在错误处理onErrorReceive中显示友好提示而非直接白屏地址栏实时显示单页应用SPAURL 变化时用 JavaScript 桥接更新地址栏 扩展挑战多标签页支持多个 Web 实例通过 Tab 切换无痕模式加载时使用incognitoMode(true)广告过滤通过onInterceptRequest拦截广告请求Javascript 桥接通过javaScriptProxy()实现 App 与网页双向通信下载管理监听onDownloadStart实现文件下载暗黑模式通过 CSS 注入prefers-color-scheme: dark运行结果完整截图官方文档HarmonyOS 应用开发文档开发者社区华为开发者论坛欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net/
学 ArkUI24:手把手教你开发一个简易浏览器 App
零基础学 ArkUI24手把手教你开发一个简易浏览器 App博主说手机浏览器是我们每天打开最多次的应用之一。你有没有想过——在 HarmonyOS 上实现一个简易浏览器其实只需要几十行代码ArkUI 内置了强大的Web 组件可以轻松加载网页、执行 JavaScript、处理页面加载事件。今天我们就用 Web 组件做一款支持导航栏、前进后退、加载进度、书签管理的简易浏览器。 应用场景在 App 内嵌网页查看内容、快速访问常用网站、开发 Hybrid 应用时调试前端页面……简易浏览器的应用场景非常广泛。我们要开发的浏览器会实现地址栏输入 URL 并加载加载进度条前进 / 后退 / 刷新网页标题显示书签管理收藏常用网站加载状态提示加载中 / 加载失败全屏模式扩展⚙️ 运行环境要求项目版本要求操作系统Windows 10/11、macOS 13 或 Ubuntu 22.04DevEco Studio5.0.3.800 及以上HarmonyOS SDKAPI 12HarmonyOS 5.0.0及以上应用模型Stage 模型开发语言ArkTS核心组件Webohos.web.webview️ 实战从零搭建简易浏览器Step 1认识 ArkUI 的 Web 组件Web组件是 ArkUI 内置的网页渲染引擎基于 Chromium 内核importwebviewfromohos.web.webview;// 在 build 中使用 Web 组件Web({src:https://www.example.com,controller:this.controller}).width(100%).height(100%).javaScriptAccess(true)// 允许 JS.domStorageAccess(true)// 允许 DOM 存储.onPageBegin((url){/* 开始加载 */}).onPageEnd((url){/* 加载完成 */}).onErrorReceive((err){/* 加载出错 */})Step 2浏览器数据结构设计// 书签数据结构interfaceBookmark{id:string;title:string;url:string;icon:string;// favicon}// WebView 控制器controller:webview.WebviewControllernewwebview.WebviewController();// 浏览历史用于前进/后退判断StatecanGoBack:booleanfalse;StatecanGoForward:booleanfalse;Step 3完整代码// pages/Index.ets — 简易浏览器主页面importwebviewfromohos.web.webview;interfaceBookmark{id:string;title:string;url:string;}EntryComponentstruct SimpleBrowser{// 状态变量 StateurlInput:stringhttps://www.example.com;StatepageTitle:string;StateisLoading:booleanfalse;StateloadProgress:number0;StatecanGoBack:booleanfalse;StatecanGoForward:booleanfalse;StateshowBookmarks:booleanfalse;Statebookmarks:Bookmark[][{id:1,title:HarmonyOS 开发文档,url:https://developer.harmonyos.com},{id:2,title:华为开发者社区,url:https://developer.huawei.com},{id:3,title:CSDN,url:https://www.csdn.net},];privatecontroller:webview.WebviewControllernewwebview.WebviewController();privatewebviewRef:stringwebview;// 页面生命周期 aboutToAppear(){// 默认加载首页this.loadUrl(this.urlInput);}// 加载 URL loadUrl(url:string){if(!url.startsWith(http://)!url.startsWith(https://)){urlhttps://url;}this.urlInputurl;this.isLoadingtrue;this.loadProgress0;this.controller.loadUrl(url);}// 导航控制 goBack(){if(this.controller.accessBackward()){this.controller.backward();}}goForward(){if(this.controller.accessForward()){this.controller.forward();}}refresh(){this.controller.refresh();}// 添加书签 addBookmark(){constnewBookmark:Bookmark{id:Date.now().toString(),title:this.pageTitle||this.urlInput,url:this.urlInput};// 去重constexiststhis.bookmarks.find(bb.urlnewBookmark.url);if(!exists){this.bookmarks.push(newBookmark);}}// 删除书签 deleteBookmark(bm:Bookmark){constidxthis.bookmarks.indexOf(bm);if(idx-1)this.bookmarks.splice(idx,1);}// UI 构建 build(){Column(){// ---- 地址栏 导航按钮 ----Row(){Button().fontSize(20).backgroundColor(transparent).fontColor(this.canGoBack?#007AFF:#ccc).enabled(this.canGoBack).onClick((){this.goBack();})Button().fontSize(20).backgroundColor(transparent).fontColor(this.canGoForward?#007AFF:#ccc).enabled(this.canGoForward).onClick((){this.goForward();})TextInput({placeholder:输入网址...,text:this.urlInput}).layoutWeight(1).height(36).backgroundColor(#F0F0F0).borderRadius(18).padding({left:12}).onSubmit((val:string){this.loadUrl(val);})Button(↻).fontSize(18).backgroundColor(transparent).fontColor(#007AFF).onClick((){this.refresh();})Button().fontSize(16).backgroundColor(transparent).onClick((){this.addBookmark();})}.width(100%).padding({top:8,bottom:4,left:8,right:8}).backgroundColor(#F8F8F8)// ---- 加载进度条 ----if(this.isLoading){Progress({value:this.loadProgress,total:100,type:ProgressType.Linear}).width(100%).height(3).color(#007AFF).value(this.loadProgress)}// ---- 书签收藏栏 ----if(this.showBookmarks){Column(){Row(){Text( 书签).fontSize(16).fontWeight(FontWeight.Bold)Button(✕).fontSize(14).backgroundColor(transparent).fontColor(#999).onClick((){this.showBookmarksfalse;})}.width(100%).justifyContent(FlexAlign.SpaceBetween)List(){ForEach(this.bookmarks,(bm:Bookmark){ListItem(){Row(){Text().fontSize(20)Column(){Text(bm.title).fontSize(14).fontWeight(FontWeight.Bold)Text(bm.url).fontSize(11).fontColor(#999).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1)}.layoutWeight(1).margin({left:8})Button(✕).fontSize(12).backgroundColor(transparent).fontColor(#FF3B30).onClick((){this.deleteBookmark(bm);})}.padding(10).width(100%)}.onClick((){this.loadUrl(bm.url);this.showBookmarksfalse;})},(bm:Bookmark)bm.id)}.height(200)}.width(100%).backgroundColor(#fff).shadow({radius:4,color:#20000000,offsetY:2})}// ---- 网页内容区域 ----Web({src:this.urlInput,controller:this.controller}).width(100%).layoutWeight(1).javaScriptAccess(true).domStorageAccess(true).onPageBegin((){this.isLoadingtrue;this.loadProgress0;}).onPageEnd((event){this.isLoadingfalse;this.loadProgress100;this.pageTitlethis.controller.title();// 更新前进/后退状态this.canGoBackthis.controller.accessBackward();this.canGoForwardthis.controller.accessForward();}).onProgressChange((event){this.loadProgressevent.newProgress;}).onErrorReceive((event){this.isLoadingfalse;console.error(页面加载失败:,event.request.getRequestUrl());}).onTitleReceive((event){this.pageTitleevent.title;})// ---- 底部状态栏 ----Row(){if(this.isLoading){Text(加载中...).fontSize(12).fontColor(#007AFF)}else{Text(this.pageTitle||this.urlInput).fontSize(12).fontColor(#999).textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1)}Text().fontSize(14).onClick((){this.showBookmarks!this.showBookmarks;})}.width(100%).padding({left:16,right:16,top:6,bottom:6}).backgroundColor(#F0F0F0).justifyContent(FlexAlign.SpaceBetween)}.width(100%).height(100%).backgroundColor(#FFFFFF)}} 核心知识点深度解析1. Web 组件的核心属性属性作用示例javascriptAccess(true)启用 JS 执行网页功能正常domStorageAccess(true)启用 localStorage记住登录状态onPageBegin开始加载回调显示加载动画onPageEnd加载完成回调隐藏加载动画onProgressChange进度变化回调更新进度条onErrorReceive加载错误回调错误提示2. WebviewController 控制方法controller.loadUrl(url)// 加载 URLcontroller.backward()// 后退controller.forward()// 前进controller.refresh()// 刷新controller.title()// 获取页面标题controller.accessBackward()// 能否后退controller.accessForward()// 能否前进3. 浏览器状态机用户输入 URL → loadUrl() → 开始加载isLoadingtrue ↓ onProgressChange → 更新进度条 ↓ onPageEnd → 标题更新 前进/后退状态更新 ↓ 加载完成isLoadingfalse⚠️ 避坑指南坑原因正确做法网页白屏忘了javascriptAccess(true)或domStorageAccess(true)必须开启这两个属性URL 加载失败用户输入了 “baidu.com” 不带协议自动补全https://前进/后退按钮无效没调用accessBackward()判断页面加载完后更新状态进度条不更新没监听onProgressChange绑定 onProgressChange 事件书签数据丢失只存在内存中用preferences持久化页面标题为空页面还没触发 onTitleReceive降级使用 URL 作为标题 最佳实践URL 自动补全用户输入不带http(s)://时自动补全减少输入错误加载进度条用 Linear Progress 给用户视觉反馈提升体验前进/后退状态灰化不能前进时按钮用灰色#ccc并enabled(false)书签去重添加前检查 URL 是否已存在错误处理onErrorReceive中显示友好提示而非直接白屏地址栏实时显示单页应用SPAURL 变化时用 JavaScript 桥接更新地址栏 扩展挑战多标签页支持多个 Web 实例通过 Tab 切换无痕模式加载时使用incognitoMode(true)广告过滤通过onInterceptRequest拦截广告请求Javascript 桥接通过javaScriptProxy()实现 App 与网页双向通信下载管理监听onDownloadStart实现文件下载暗黑模式通过 CSS 注入prefers-color-scheme: dark运行结果完整截图官方文档HarmonyOS 应用开发文档开发者社区华为开发者论坛欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net/