HarmonyOS元服务开发实践:桌面卡片字典
一、项目说明
1.DEMO创意为卡片字典。
2.不同卡片显示不同内容:微卡、小卡、中卡、大卡,根据不同卡片特征显示同一个字的不同内容,基于用户习惯可选择喜欢的卡片。
3.万能卡片刷新:用户点击卡片刷新按钮查看新内容,同时卡片设置了定时刷新,让用户每天看到的卡片都是新的文字,便于用户学习和查阅。
4.元服务内具有搜索功能,用户可以通过搜索查询相应的字和解释,采用了类似现在用户习惯的上下滑动方式来进行逐字详细阐述。
5.基于API9、ArkTS语言开发,通过serverless云服务实现注册、登录等功能。
二、元服务效果
1.万能卡片效果


2.元服务内页

三、项目开发
1.环境搭建
软件要求:
DevEco Studio版本:DevEco Studio 3.1 Release及以上版本。
HarmonyOS SDK版本:API version 9及以上版本。
硬件要求:
设备类型:华为手机或运行在DevEco Studio上的华为手机设备模拟器。
HarmonyOS系统:3.1.0 Developer Release及以上版本。
2.主要代码结构解读

entry/src/main/ets: 文件入口
common:公共资源文件
images:公共图片资源
Constants.ts:公共常量
CountryViewModel.ts:国家号码类
LazyFE_Class.ets:懒数据加载类
Log.ts:日志类
components:封装组件文件
database:数据库封装类
data_cyhz.ets:数据文件
entryability:应用/服务入口
entryformability:卡片服务
pages:应用/服务页面
Auth.ets:认证授权
CloudFunction.ets:云函数
CloudProject.ets:云项目
CloudStorage.ets:云存储
Index.ets:主页
User_Login.ets:登录页
User_SignUp.ets:注册页
User_VerifyCodeLogin.ets:验证码登录页
services:后台操作类
widget:服务卡片
resources:资源文件目录
3.进入应用说明
由于创建的是云模板项目,所以无需额外配置SDK依赖,只需要注意的是,云模板的初始集成sdk位置不一样,所以我们还是在应用初始化阶段使用context初始化SDK,推荐在entryability的onCreate中进行。

4.首页
我们需要给应用添加底部菜单栏,用于切换不同的应用模块,由于各个模块之间属于完全独立的情况,并且不需要每次切换都进行界面的刷新,所以我们用到了Tabs,TabContent组件。

本应用一共有首页、我的两个模块,分别对应Tabs组件的两个子组件TabContent。
首页包含搜索文字和滑动浏览信息两个模块,具体代码实现我们将在下边分模块进行说明。
搜索文字:主要用到Search组件,通过搜索文字来跳转到相应的文字展示信息,主要代码如下:

...
//常用汉字搜索栏
Column() {Search({ value: this.submitValue, placeholder: '汉字搜索', controller: this.search }).searchButton('搜索').placeholderColor(Color.Grey).textFont({ size: 14, weight: 400 }).margin({ left: 20, right: 20 }).onSubmit((value: string) => {this.submitValue = valuefor (let i = 0; i < wz.length; i++) {const element: any = wz[i];if (this.submitValue == element.zi) {this.swiperIndex = ithis.submitValue = ''}}}).onChange((value: string) => {this.changeValue = value})
}.width("100%").margin({ top: 20, bottom: 20 })
......
浏览信息模块:主要用到swiper组件,通过数据的懒加载行为,来预缓存数据,通过滑动页面来展示文字信息,主要代码如下:

...//常用汉字轮播部分
Column() {Swiper(this.swiperController) {LazyForEach(this.data_wz, (item: any) => {Column() {...}.width("100%").height("100%").justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Start)}, item => item)}.vertical(true).cachedCount(2).autoPlay(false).indicator(false).loop(false).duration(400).itemSpace(0).curve(Curve.Linear).cachedCount(3).index(this.swiperIndex).disableSwipe(this.disableSwipe).onChange((index: number) => {console.info("swiper:" + index.toString())this.swiperIndex = index})
}.width("100%")...
5.我的
我的页包含游客登陆、用户登录两个模块。
其中游客登陆不显示登录信息以及应用部分功能,仅能使用部分应用能力;
用户登录显示用户部分信息,并展开应用所有功能,需要用户注册登录;
具体代码实现我们将在下边分模块进行说明。
游客登录:

...//游客登陆状态
if (this.isVisitor) {//头像信息Column() {Image($r('app.media.icon')).width(90).objectFit(ImageFit.Contain).borderRadius(50)Text(this.isVisitor ? "游客_" : this.userName).fontSize(16).margin(20)Button(this.isLogin ? "退出" : "登录", { type: ButtonType.Capsule }).fontSize(14).width('120').height('30').backgroundColor(0xf48fb1).onClick(() => {router.replaceUrl({url: "pages/User_Login"})})}.width('90%').height('240').borderRadius(12).margin({ top: 20 }).backgroundColor(0xFFFFFF).shadow({ radius: 12, color: 0xCECECE, offsetX: 4, offsetY: 6 }).justifyContent(FlexAlign.Center)
}...
用户登录:

...//已经登陆状态if (!this.isVisitor) {//头像信息Column() {
...}.width('90%').height('240').borderRadius(12).margin({ top: 20 }).backgroundColor(0xFFFFFF).shadow({ radius: 12, color: 0xCECECE, offsetX: 4, offsetY: 6 }).justifyContent(FlexAlign.Center)//选择项Column() {...
}.width('100%')
.height("100%")
.backgroundColor(0xF5F5F5)
.justifyContent(FlexAlign.Start)
6.注册登录页
让用户进行账号注册,能够完全使用应用。


核心代码:
....onClick(() => {if (this.phoneNumber !== '' && this.password !== '') {let verifyCodeSettings = new VerifyCodeSettingBuilder().setAction(VerifyCodeAction.REGISTER_LOGIN).setLang('zh_CN').setSendInterval(60).build();agconnect.auth().requestPhoneVerifyCode(this.countryCode, this.phoneNumber, verifyCodeSettings).then(verifyCodeResult => {this.startTimer()//验证码申请成功}).catch(error => {//验证码申请失败Prompt.showToast({ message: "请输入正确的手机号和密码" + JSON.stringify(error) })});}else {Prompt.showToast({ message: "手机号和密码不能为空" })}
})......
.......onClick(() => {if (this.phoneNumber !== '' && this.password !== '') {let user = new PhoneUserBuilder().setCountryCode(this.countryCode).setPhoneNumber(this.phoneNumber).setPassword(this.password) //可以给用户设置初始密码。填写后后续可以用密码来登录.setVerifyCode(this.VerifyCode).build();agconnect.auth().createPhoneUser(user).then(result => {// 创建用户成功AppStorage.Set('phoneNumber', user.phoneNumber)AppStorage.Set('password', user.password)AppStorage.Set('isVisitor', false)AppStorage.Set('isLogin', true)AppStorage.Set('userName', user.phoneNumber)router.pushUrl({url: "pages/Index"})}).catch(error => {// 创建用户失败Prompt.showToast({ message: "注册失败," + JSON.stringify(error),duration:4 })})} else {Prompt.showToast({ message: "手机号和密码不能为空" })}
})
7.其他云服务
说明:这是云模板初始业务,如有其他业务需求,可自行添加。

四、卡片开发
按需求添加卡片,也可以只用初始创建卡片,修改相关卡片参数即可。
1.创建卡片



2.初始卡片修改相关参数
打开resources/base/profile目录下的form_config.json文件,按需修改参数


3.卡片加载与获取数据
卡片加载更新部分由EntryFormAbility.ts文件完成,这里可参考官方文档操作即可。
由于没有连接到后台数据部分,所以我们这里采用自定义模拟数据,然后在每次卡片挂载到桌面时,随机选取卡片内容,代码如下:


...
aboutToAppear() {let idx = Math.floor((Math.random() * wz_arr.length))this.zi = wz_arr[idx].zithis.pinYin = wz_arr[idx].pinYinthis.buShou = wz_arr[idx].buShouthis.biHua = wz_arr[idx].biHuathis.fanTi = wz_arr[idx].fanTithis.near_words = wz_arr[idx].near_wordsthis.reverse_words = wz_arr[idx].reverse_wordsthis.explain = wz_arr[idx].explain.toString()
}...
4.卡片主要代码

...Column() {//微卡Stack() {Text(this.zi).width("100%").textAlign(TextAlign.Center).fontSize(30).fontColor('#1f1f1f').fontWeight(600).margin({right:20})Row(){Image("/common/images/R2.png").width(18).height(18).margin({right:"15%"}).objectRepeat(ImageRepeat.NoRepeat).onClick(()=>{this.rotateAngle = 180this.aboutToAppear()}).rotate({ angle: this.rotateAngle }).animation({duration:300,curve: Curve.Linear,playMode: PlayMode.Normal})}.width("100%").justifyContent(FlexAlign.End)}.width("100%").height(72)//小卡、中卡Flex({direction:FlexDirection.Column,wrap:FlexWrap.Wrap,justifyContent:FlexAlign.Start}){Column(){Text("拼音:"+this.pinYin).fontSize(14).margin({left:15})Text("部首:"+this.buShou).fontSize(14).margin({top:4,left:15})Text("笔画:"+this.biHua).fontSize(14).margin({top:4,left:15})Text("繁体:"+this.fanTi).fontSize(14).margin({top:4,left:15})}.width(208).justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Start)Column(){Text("近义词:"+this.near_words).fontSize(12).margin({right:15})Text("反义词:"+this.reverse_words).fontSize(12).margin({top:4,right:15})}.justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Start)}.width("100%").height(102)//大卡Column(){Text("解释:").width("100%").textAlign(TextAlign.Start).fontSize(12).margin({left:15,right:15})Text(this.explain).fontSize(14).margin({top:4,left:15,right:15})}.width("100%").height("100%").justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Start)
}
.width("100%")
.alignItems(HorizontalAlign.Center)
.backgroundImage("/common/images/cywz.jpg")
.backgroundImageSize(ImageSize.Cover)
.onClick(() => {postCardAction(this, {"action": this.ACTION_TYPE,"abilityName": this.ABILITY_NAME,"params": {"message": this.MESSAGE,}});
})...
五、项目运行



六、结语
各位感兴趣的开发者可以点击进入元服务官网,详细了解元服务、万能卡片相关信息。大家还可以在华为手机的负一屏、华为应用市场元服务专区体验本文作者及团队已经上架运营的元服务-成语心情,用万能卡片按照自己的心情来刷刷成语吧。

相关文章:
HarmonyOS元服务开发实践:桌面卡片字典
一、项目说明 1.DEMO创意为卡片字典。 2.不同卡片显示不同内容:微卡、小卡、中卡、大卡,根据不同卡片特征显示同一个字的不同内容,基于用户习惯可选择喜欢的卡片。 3.万能卡片刷新:用户点击卡片刷新按钮查看新内容,同时…...
xLua学习
xLua教程:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/XLua%E6%95%99%E7%A8%8B.md xLua配置:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/configure.md FAQ:https://github.com/Tencent/xLua/blob/maste…...
Web3到底是个啥?
Web3到底是个啥? Web3是近两年来科技领域最火热的概念之一,但是目前对于Web3的定义却仍然没有形成标准答案,相当多对于Web3的理解,都是建立在虚拟货币行业(即俗称的“币圈”)的逻辑基础之上的。 区块链服务…...
pycharm、idea、golang等JetBrains其他IDE修改行分隔符(换行符)
文章目录 pycharm、idea、golang系列修改行分隔符我应该选择什么换行符JetBrains IDE,默认行分隔符 是跟随系统修改JetBrains IDE,默认行分隔符 pycharm、idea、golang系列修改行分隔符 一般来说,不同的开发环境和项目对换行格式的使用偏好不同: Windo…...
ThinkPHP函数深度解析
ThinkPHP是一个具有丰富功能和强大灵活性的PHP开发框架。在这篇文章中,我们将详细介绍ThinkPHP的一些关键函数,以帮助开发人员更好地理解和使用这个框架。 1. 入门:ThinkPHP的核心函数 1.1 C()函数 C()函数用于读取和设置配置参数。它是Thin…...
【java】【maven】【高级】MAVEN聚合继承属性等
目录 1、模块开发与设计 2、聚合 2、继承 3、属性 4、版本管理 5、资源配置 6、多环境配置 7、多环境开发配置 8、跳过测试 9、私服 前言:maven的高级使用包含分模块开发与设计、聚合、继承、属性、版本管理、资源配置、多环境配置、多环境开发配置、跳过…...
LeetCode150道面试经典题-合并两个有序数组(简单)
合并两个有序数组 题目: 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 注意&a…...
记录 运维三剑客一件部署的的docker-compose,yml文件
CAdvisor: 收集 InfluxDB: 存储 Grafana: 展示 version: 3.1volumes:grafana_data: {}services:influxdb:image: tutum/influxdb:0.9restart: alwaysenvironment:- PRE_CREATE_DBcadvisorports:- "8083:8083"- "8086:8086"volumes:- ./data/inf…...
Xposed框架开发
文章目录 xpose插件开发步骤清单文件新建一个类(插件入口点)设置入口点 Hook第一个实例zhuceji.apk一些常用的HOOKHookH5PluginHookProxyPluginHookSystem 资料Xposed原理初探 xpose插件开发步骤 magisk安装与配置 Xpose Framework API LSPosed magisk …...
2.13 Android ebpf非网络相关帮助函数API汇总(十二 本章完)
1.long bpf_user_ringbuf_drain(struct bpf_map *map, void *callback_fn, void *ctx, u64 flags) 描述:从指定的用户环形缓冲区中排出样本,并为每个此类样本调用提供的回调: long (*callback_fn)(struct bpf_dynptr *dynptr, void *ctx); 如果callback_fn返回0,帮助函数…...
关于游戏的笔记
关于搭建秦时明月2一键端,并且开启秘境神秘商人东海寻仙幻化 1.该游戏下主要的目录 gm端 服务框架 服务端 2.修改对应的文件 C:\qs\Q2Server\server\conf_common\ManagerAddress.xmlC:\qs\Q2Server\server\conf_manager\GateServer.xml修改ip 3.启动gm startup…...
vue diff 前后缀+最长递增子序列算法
文章目录 查找相同前后缀通过前后缀位置信息新增节点通过前后缀位置信息删除节点 中间部份 diff判断节点是否需要移动删除节点删除未查找到的节点删除多余节点 移动和新增节点最长递增子序列 求解最长递增子序列位置信息 查找相同前后缀 如上图所示,新旧 children 拥…...
【Python】Locust持续优化:InfluxDB与Grafana实现数据持久化与可视化分析
目录 前言 influxDB 安装运行InfluxDB 用Python 上报数据到influxdb ocust 数据写入到 influx Locust的生命周期 上报数据 优化升级 配置Grafana 总结 资料获取方法 前言 在进行性能测试时,我们需要对测试结果进行监控和分析,以便于及时发现问…...
数组模拟循环链表
5073. 空闲块 - AcWing题库 数组模拟循环链表 /*从当前位置开始遍历空闲块链表(初始是从地址最小的第一个空闲块开始),寻找满足条件的最小块 (即:大于等于请求空间的最小空闲块,如果有多个大小相同的最小空…...
第三章 图论 No.5最小生成树之虚拟源点,完全图与次小生成树
文章目录 虚拟源点:1146. 新的开始贪心或kruskal性质:1145. 北极通讯网络最小生成树与完全图:346. 走廊泼水节次小生成树:1148. 秘密的牛奶运输 虚拟源点:1146. 新的开始 1146. 新的开始 - AcWing题库 与一般的最小…...
RESTful API的讲解以及用PHP实现RESTful API
RESTful API是什么 RESTful是一种设计风格,是一种用于构建Web服务的架构。RESTful API是一种基于REST(Representational State Transfer)架构风格的Web服务接口设计规范。它强调使用HTTP协议中的请求方法(例如GET、POST、PUT、DEL…...
Spring中@Component和@Bean的区别
1. 用途不同 Component用于标识普通类 Bean是在配置类中声明和配置Bean对象 2. 使用方式不同 Component是一个类级别的注解,Spring通过ComponentScan注解扫描并注册为Bean. Bean是一个方法级别的注解,在配置类中手动声明和配置Bean 3. 控制权不同 Component注解修饰的类使…...
【问题解决】mysql 数据库字符串分割之后多行输出方法
背景: 项目需要从一张表查询出来数据插入到另一张表,其中有一个字段是用逗号分隔的字符串,需要多行输入到另一张表,那么这个如何实现呢 方案: 下面先粘贴下sql语句: select SUBSTRING_INDEX(SUBSTRING_…...
flutter开发实战-时间显示刚刚几分钟前几小时前
flutter开发实战-时间显示刚刚几分钟前几小时前 在开发中经常遇到从服务端获取的时间戳,需要转换显示刚刚、几分钟前、几小时前、几天前、年月日等格式。 一、代码实现 static String timeFormatterChatTimeStamp(int seconds) {try {int nowDateSeconds (DateTi…...
导出LLaMA等LLM模型为onnx
通过onnx模型可以在支持onnx推理的推理引擎上进行推理,从而可以将LLM部署在更加广泛的平台上面。此外还可以具有避免pytorch依赖,获得更好的性能等优势。 这篇博客(大模型LLaMa及周边项目(二) - 知乎)进行…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...
break 语句和 continue 语句
break语句和continue语句都具有跳转作用,可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...
