尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
HarmonyOS7股票组合看板实战:持仓汇总与盈亏计算
文章目录前言StockItem_65tq 同时保存行情和持仓组合收益是一步一步推出来的搜索只影响列表不影响总资产涨跌颜色来自单只股票不来自组合selectedTab 目前只做高亮完整代码最后总结前言股票组合看板的重点不是把列表做漂亮而是把几个金额关系算对。持仓市值、持仓成本、盈亏金额、盈亏率这几个数字一旦口径不清页面再精致也没用。这个 Demo 的数据量很小但刚好能讲清楚组合看板里最基础的一套计算链路。这页没有买入卖出、没有实时行情订阅也没有真正的 tab 排序。它目前做的是展示持仓按名称或代码搜索并根据持仓数量、当前价和成本价计算组合收益。StockItem_65tq同时保存行情和持仓每只股票对象里既有行情字段也有持仓字段。price、change、changeRate、volume更像行情数据held和cost则是用户自己的持仓信息。interfaceStockItem_65tq{symbol:stringname:stringprice:numberchange:numberchangeRate:numbervolume:stringheld:numbercost:number}这个模型适合 Demo因为所有信息在一个数组里列表和汇总都能直接算。真实产品里通常会把行情和持仓拆开行情来自市场接口会高频变化持仓来自账户系统变化频率低得多。拆开之后前端再按股票代码合并展示。组合收益是一步一步推出来的总市值是当前价乘以持仓数量总成本是成本价乘以持仓数量总盈亏是两者相减盈亏率再除以总成本。代码把这几个值写成 getter而不是保存成状态。gettotalValue():number{returnthis.stocks.reduce((sum,s)sums.price*s.held,0)}gettotalCost():number{returnthis.stocks.reduce((sum,s)sums.cost*s.held,0)}gettotalProfit():number{returnthis.totalValue-this.totalCost}getprofitRate():number{returnthis.totalCost0?(this.totalProfit/this.totalCost)*100:0}这个顺序很重要。totalProfit依赖totalValue和totalCostprofitRate又依赖totalProfit。只要stocks变化所有汇总数字都会重新计算不需要手动同步。profitRate里判断this.totalCost 0也值得保留。虽然示例数据都有成本但真实数据里可能出现空持仓或成本为 0 的情况直接除会得到无意义结果。搜索只影响列表不影响总资产搜索框绑定searchText列表渲染读取filteredStocks。如果没有搜索词返回全部股票有搜索词时同时匹配股票代码和中文名称。getfilteredStocks():StockItem_65tq[]{if(!this.searchText)returnthis.stocksreturnthis.stocks.filter(ss.symbol.toLowerCase().includes(this.searchText.toLowerCase())||s.name.includes(this.searchText))}这里有一个产品口径要注意搜索只过滤列表不影响顶部总市值和总盈亏。也就是说用户搜索 TSLA 时顶部仍然显示整个组合的资产不是搜索结果的资产。这个选择没有绝对对错但要保持一致。如果想让搜索后的汇总跟着变就应该把汇总也改成基于filteredStocks计算。涨跌颜色来自单只股票不来自组合列表里单只股票的涨跌幅颜色由changeRate决定顶部组合盈亏颜色由totalProfit决定。这两个指标不能混在一起一只股票当天上涨不代表这只持仓一定盈利因为用户成本价可能更高。Text(${stock.changeRate0?:}${stock.changeRate.toFixed(2)}%).fontColor(#FFF).backgroundColor(stock.changeRate0?#2ED573:#FF4757)当前列表还展示了“成本 $xxx”但没有单独展示每只股票的持仓盈亏。如果要让看板更有投资分析价值我会补一个单股盈亏(stock.price - stock.cost) * stock.held再显示盈亏率(stock.price - stock.cost) / stock.cost。selectedTab目前只做高亮页面上有“持仓、涨幅、跌幅”三个 tab点击后会改变selectedTab但filteredStocks并没有读取这个状态。因此当前 tab 只改变视觉选中态不会真的排序或过滤列表。.onClick(()this.selectedTabidx)如果要补完整最直接的做法是在filteredStocks之后再根据selectedTab排序持仓页按市值排序涨幅页按changeRate从高到低跌幅页从低到高。这样 tab 才真的参与数据展示而不是只停留在 UI 状态。这也是这篇代码最适合继续练习的地方先把计算口径固定再把搜索、排序和汇总之间的关系讲清楚。资产类页面看似都是数字真正麻烦的是每个数字到底代表什么范围。完整代码下面保留案例完整代码方便你直接对照学习、复制和重构。import{router}fromkit.ArkUIinterfaceStockItem_65tq{symbol:stringname:stringprice:numberchange:numberchangeRate:numbervolume:stringheld:numbercost:number}EntryComponentstruct StockPortfolioDashboard{Statestocks:StockItem_65tq[][{symbol:AAPL,name:苹果,price:189.5,change:2.3,changeRate:1.23,volume:52.3M,held:10,cost:175.0},{symbol:TSLA,name:特斯拉,price:248.7,change:-5.1,changeRate:-2.01,volume:38.1M,held:5,cost:260.0},{symbol:MSFT,name:微软,price:415.2,change:3.8,changeRate:0.92,volume:21.7M,held:8,cost:390.0},{symbol:GOOGL,name:谷歌,price:172.4,change:-1.2,changeRate:-0.69,volume:18.5M,held:12,cost:168.0},{symbol:AMZN,name:亚马逊,price:198.3,change:4.5,changeRate:2.32,volume:29.8M,held:6,cost:185.0},]StateselectedTab:number0StatesearchText:stringgettotalValue():number{returnthis.stocks.reduce((sum,s)sums.price*s.held,0)}gettotalCost():number{returnthis.stocks.reduce((sum,s)sums.cost*s.held,0)}gettotalProfit():number{returnthis.totalValue-this.totalCost}getprofitRate():number{returnthis.totalCost0?(this.totalProfit/this.totalCost)*100:0}getfilteredStocks():StockItem_65tq[]{if(!this.searchText)returnthis.stocksreturnthis.stocks.filter(ss.symbol.toLowerCase().includes(this.searchText.toLowerCase())||s.name.includes(this.searchText))}build(){Column(){// HeaderRow(){Image($r(app.media.startIcon)).width(24).height(24).onClick(()router.back())Text(股票组合).fontSize(18).fontWeight(FontWeight.Bold).layoutWeight(1).textAlign(TextAlign.Center)Text(⚙).fontSize(20).fontColor(#555)}.width(100%).padding({left:16,right:16,top:12,bottom:12})// Portfolio summaryColumn(){Text(总市值).fontSize(13).fontColor(#FFFFFFAA).margin({bottom:4})Text(\$\${this.totalValue.toFixed(2)}\).fontSize(28).fontWeight(FontWeight.Bold).fontColor(#FFF)Row(){Text(\\${this.totalProfit0?:}$\${this.totalProfit.toFixed(2)}\).fontSize(14).fontColor(this.totalProfit0?#2ED573:#FF4757)Text(\(\${this.profitRate0?:}\${this.profitRate.toFixed(2)}%)\).fontSize(14).fontColor(this.totalProfit0?#2ED573:#FF4757)}.margin({top:4})Text(累计持仓盈亏).fontSize(11).fontColor(#FFFFFFAA).margin({top:4})}.width(calc(100% - 32vp)).backgroundColor(#007AFF).borderRadius(16).padding(20).margin({bottom:12}).linearGradient({colors:[[#007AFF,0.0],[#0056CC,1.0]],angle:135})// SearchTextInput({placeholder:搜索股票名称或代码,text:this.searchText}).onChange(vthis.searchTextv).width(calc(100% - 32vp)).backgroundColor(#FFF).borderRadius(20).margin({bottom:12})// TabsRow(){ForEach([持仓,涨幅,跌幅],(tab:string,idx:number){Text(tab).fontSize(14).fontColor(this.selectedTabidx?#007AFF:#888).borderWidth({bottom:this.selectedTabidx?2:0}).borderColor(#007AFF).padding({bottom:8,left:16,right:16}).onClick(()this.selectedTabidx)})}.width(100%).padding({left:16}).margin({bottom:8})// Stock listList({space:8}){ForEach(this.filteredStocks,(stock:StockItem_65tq){ListItem(){Row(){Column(){Text(stock.symbol).fontSize(16).fontWeight(FontWeight.Bold).fontColor(#333)Text(stock.name).fontSize(12).fontColor(#888)Text(\持仓 \${stock.held}股\).fontSize(11).fontColor(#AAA).margin({top:2})}.alignItems(HorizontalAlign.Start).layoutWeight(1)Column(){Text(\$\${stock.price.toFixed(2)}\).fontSize(15).fontWeight(FontWeight.Bold).fontColor(#333)Text(\\${stock.change0?:}\${stock.change.toFixed(2)}\).fontSize(12).fontColor(stock.change0?#2ED573:#FF4757)}.alignItems(HorizontalAlign.End).margin({right:8})Column(){Text(\\${stock.changeRate0?:}\${stock.changeRate.toFixed(2)}%\).fontSize(13).fontColor(#FFF).backgroundColor(stock.changeRate0?#2ED573:#FF4757).borderRadius(6).padding({left:8,right:8,top:4,bottom:4})Text(\成本 $\${stock.cost.toFixed(0)}\).fontSize(11).fontColor(#AAA).margin({top:4})}.alignItems(HorizontalAlign.End)}.width(100%).backgroundColor(#FFF).borderRadius(12).padding(14).shadow({radius:4,color:#0000001A,offsetY:2})}})}.layoutWeight(1).padding({left:16,right:16})}.width(100%).height(100%).backgroundColor(#F5F5F5)}}最后总结股票组合看板 这个案例并不靠复杂技巧取胜它更像一个结构扎实、逻辑完整的业务页面样板。把这篇文章里的状态设计、函数组织和页面分层吃透之后你再去写同类型功能速度会明显快很多。
RELATED

相关推荐

C++ string类深度解析:从构造、迭代器到现代语法与性能优化

C++ string类深度解析:从构造、迭代器到现代语法与性能优化

1. 项目概述:为什么C程序员必须精通string类?在C的世界里,string类就像空气和水一样,无处不在,却又常常被我们习以为常地使用。很多刚入门的C开发者,尤其是从C语言转过来的朋友,常常会犯一个错误…

📅 2026/8/24 2:19:40
ESP8266实战指南:从AT指令到网络通信模式全解析

ESP8266实战指南:从AT指令到网络通信模式全解析

1. ESP8266入门:从零认识这个物联网神器第一次拿到ESP8266模块时,我完全被这个小东西震惊了——它比硬币大不了多少,却内置了完整的Wi-Fi功能和32位处理器。作为物联网开发的入门神器,ESP8266已经成为全球最受欢迎的Wi-Fi模块之一…

📅 2026/8/24 2:19:40
C++算法项目实战:TheAlgorithms/C-Plus-Plus环境配置与高效学习指南

C++算法项目实战:TheAlgorithms/C-Plus-Plus环境配置与高效学习指南

1. 项目概述与核心价值 如果你正在学习C,或者想深入理解算法和数据结构,但苦于找不到一个结构清晰、代码规范、覆盖全面的实战项目来练手,那么《TheAlgorithms/C-Plus-Plus》这个开源项目绝对值得你花时间研究。它不是一个简单的代码仓库&am…

📅 2026/8/25 16:53:54
MORE NEWS

更多资讯

📰

MindsHub Cowork 如何用 make pack-local 从本地未提交源码打包 macOS .app

MindsHub Cowork 如何用 make pack-local 从本地未提交源码打包 macOS .app 【免费下载链接】mindshub The unified workspace where open-source models get things done for you. 项目地址: https://gitcode.com/GitHub_Trending/mi/mindshub 当你在前端或 backend/co…

📰

agno 知识库如何配置混合搜索并用 Cohere reranker 做两阶段重排提升检索质量?

agno 知识库如何配置混合搜索并用 Cohere reranker 做两阶段重排提升检索质量? 【免费下载链接】agno Build, run, and manage agent platforms. 项目地址: https://gitcode.com/GitHub_Trending/ag/agno 如果你用 agno 的 Knowledge 组件给 Agent 接入文档检…

📰

Fast Video Cutter Joiner:轻量化视频处理工具的核心技术与应用

1. Fast Video Cutter Joiner 核心功能解析Fast Video Cutter Joiner 是一款集视频剪切、合并与格式转换于一体的轻量化工具,其6.9.5.0便携版仅18.9MB的体积却提供了专业级的视频处理能力。作为一款多语言支持的工具,它特别适合需要快速处理视频素材但又…

📰

G-Helper完整免费替代华硕Armoury Crate的单文件工具

G-Helper完整免费替代华硕Armoury Crate的单文件工具 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, Expertbook, RO…

📰

能源汇阅[DP01] | N015 电价没有变天,企业用电账本算法正在彻底革新

摘要:随着电力市场改革深化、现货市场扩容、分时电价精细化及绿电政策下沉,企业用电成本不再是固定“一口价”模式。本轮改革并非电价普涨,而是将电力成本拆解为电能量、调节能力、可靠容量、绿色环境四大独立维度,重构企业用电成…

📰

OpenProject 快速上手:4 步搭建带甘特图的开源自托管项目管理平台

OpenProject 快速上手:4 步搭建带甘特图的开源自托管项目管理平台 【免费下载链接】openproject OpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile pl…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬