arkts-9 项目相关

一 项目结构 创建参考

  • 文件夹普遍小写
  • 文件普遍大写
js 复制代码
---- src/main/ets
---- constants  // 定义宏 枚举之类的
     ---------- PageConstants
     ---------- CommonConstants
     ---------- NetworkState
---- model  // 定义模型
---- network  // 网络
---- utils  // 工具类
---- view  // 定义模型
     ---------- components //UI组件
     ---------- pages // 页面
---- viewModel  // 业务封装

二 签名报错处理

js 复制代码
// 打开项目根目录的 `build-profile.json5` 文件  ⚠️ 注意不是src/main中的

{
  "app": {
    "signingConfigs": [],  // 清空数组
    "products": [
      {
        "name": "default",
        // "signingConfig": "default",  // 删除或注释
        "targetSdkVersion": "5.1.1(19)",
        "compatibleSdkVersion": "5.0.0(12)",
        "runtimeOS": "HarmonyOS",
        "buildOption": {
          "strictMode": {
            "caseSensitiveCheck": true,
            "useNormalizedOHMUrl": true
          }
        }
      }
    ],
    // ... 其他配置
  }
}

三 修改项目签名

3.1 修改 bundleName**

打开工程根目录下 AppScope/app.json5 文件,修改 bundleName 字段值

js 复制代码
{
  "app": {
    "bundleName": "com.example.myapp",  // 修改为新的包名
    "vendor": "example",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:app_icon",
    "label": "$string:app_name"
  }
}

3.2 清除签名配置

打开与 AppScope 同级目录下的项目级 build-profile.json5 文件,将 signingConfigs 字段清空

js 复制代码
{
  "app": {
    "signingConfigs": []  // 清空签名配置,后续重新生成
  }
}

3.3 清理与重新签名

  1. 在 DevEco Studio 中执行 Build → Clean Project,清理构建缓存6
  2. 删除真机/模拟器上已安装的旧包名应用6
  3. 关闭 IDE 后重新打开,重新配置自动签名6
  4. 重新编译运行,验证应用正常启动

四 写请求

  • 两种写法在性能和线程行为上 完全等价
  • 函数可以隐示声明返回值
js 复制代码
// 写法一:async/await(同步风格,可读性好)
async function fetchData() {
  try {
    const response = await getArticleList(pageIndex, cid)
    return new BaseResult<BaseListBean<ArticleBean[]>>(NetworkState.SUCCESS, response)
  } catch (error) {
    return new BaseResult<BaseListBean<ArticleBean[]>>(NetworkState.ERROR, undefined, error as BusinessError)
  }
}

// 写法二:Promise 链式调用(等价,只是写法不同)
// 注意三个return

function fetchData() {
  return getArticleList(pageIndex, cid)
    .then((response: BaseBean<BaseListBean<ArticleBean[]>>) => {
      return new BaseResult<BaseListBean<ArticleBean[]>>(NetworkState.SUCCESS, response)
    })
    .catch((error: CommonType) => {
      return new BaseResult<BaseListBean<ArticleBean[]>>(NetworkState.ERROR, undefined, error as BusinessError)
    })
}

五 断言

  • undefinednull 可以被断言为 任何类型

六 类型判断

typeof 是一元运算符,用来判断一个值的数据类型,返回一个字符串。

值类型 typeof 返回 示例
字符串 'string' typeof 'hello'
数字 'number' typeof 123
布尔值 'boolean' typeof true
undefined 'undefined' typeof undefined
对象 'object' typeof {}
数组 'object' typeof []
null 'object' typeof null ⚠️ 历史 bug
函数 'function' typeof (()=>{})
Symbol 'symbol' typeof Symbol()
BigInt 'bigint' typeof 123n
js 复制代码
if (typeof arr === 'object') {
  console.log('arr 是对象');
}
if (typeof('嘻嘻') =='object') {
    console.log('arr 是对象11');
} else {
    console.log('嘻嘻是字符串');
}

七 返回 : payload is AxiosError<T, D>;

swift 复制代码
// ts的语法 

// 返回值 通过函数的真实返回类型推断

export function isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;

payload is AxiosError 不是返回值 是告诉开发者 这个方法是判断payload 是不是AxiosError错误的函数

八 layoutWeight

  • 布局权重: 父组件高度,先减去内部子组件的固定高度,剩余的高度的百分比
  • 同时设置固定长度和layoutWeight()权重, 权重生效
js 复制代码
Row() {

  // 权重1,占主轴剩余空间1/3 为:(100% - 30%) * 1/3
  // ⚠️ width: '30%'被 .layoutWeight(1)覆盖了, 同时设置 权重生效
  Text('layoutWeight(1)')
    .size({ width: '30%', height: 110 }).backgroundColor(0xFFEFD5).textAlign(TextAlign.Center)
    .layoutWeight(1)
    
  // 权重2,占主轴剩余空间2/3 为:(100% - 30%) * 2/3
  Text('layoutWeight(2)')
    .size({ width: '30%', height: 110 }).backgroundColor(0xF5DEB3).textAlign(TextAlign.Center)
    .layoutWeight(2)
    
  // 未设置layoutWeight属性,组件按照自身尺寸渲染
  Text('no layoutWeight')
    .size({ width: '30%', height: 110 }).backgroundColor(0xD2B48C).textAlign(TextAlign.Center)
}
.size({ width: '90%', height: 140 })
.backgroundColor(0xAFEEEE)

九 布局

9.1 list

  • 组件的子组件总高 小于 父组件高 组件上子组件自适应

如果List组件主轴方向没有设置尺寸,当List子组件主轴方向总尺寸小于List的父组件尺寸时,List主轴方向尺寸自动适应子组件的总尺寸。

  • 组件的子组件总高 大于 父组件高 组件按父组件高适应 如果子组件主轴方向总尺寸超过List父组件尺寸时,List主轴方向尺寸适应List的父组件尺寸。

9.2 tabs

  • TabContent组件不支持设置通用宽度属性,其宽度默认撑满Tabs父组件。
  • TabContent组件不支持设置通用高度属性,其高度由Tabs父组件高度与TabBar组件高度决定。

十 引用传递

NewsData-master

js 复制代码
// NewsList.ets 页面

@Component
export default struct NewsList {
  @State @Watch('newCustom') newsModel: NewsModel = new NewsModel(); // 默认的总模型
  
  newCustom() { // 被监听方法
   // ......
 }   
    
 build() {
  Column() {
    // ......
  }
  .width(Const.FULL_WIDTH) // 100%
  .height(Const.FULL_HEIGHT)
  .justifyContent(FlexAlign.Center)
  .onTouch((event: TouchEvent | undefined) => { //监听手指在组件上
      // 调用其他页面的公共方法
      listTouchEvent(this.newsModel, event);
  })
}   
}
js 复制代码
// PullDownRefresh.ets

export function listTouchEvent(that: NewsModel, event: TouchEvent) {
  // 接收that
  touchUpPullRefresh(that);
}  

export function touchUpPullRefresh(that: NewsModel) {
   // 网络请求
   let self = that;
   NewsViewModel.getNewsList(that.currentPage, that.pageSize, Const.GET_NEWS_LIST).then((data: NewsData[]) => {
     self.newsData = data; // 重新赋值 非修改某属性
   }
   
} 

十一 三方库版本

^1.0.31.0.3 的核心区别在于:前者是 范围版本号 ,允许安装满足条件的更高版本;后者是 精确版本号,只安装指定版本。

oh-package-lock.json5 对比

js 复制代码
-  "@abner/refresh_v2@^1.0.3": "@abner/refresh_v2@1.0.3",

   
   "packages": {

-  "@abner/refresh_v2@1.0.3": {

-    "version": "1.0.3",

-    "integrity": "sha512-Zv9uXqkaZB1yY+aNOTh4cEEQCgc34EgKkzy6qTx3lCRM1wGmuEZfvuGEw2ql3bNb6nqHvbgt25LMVu5Fs6tyyw==",

-    "resolved": "https://ohpm.openharmony.cn/ohpm/@abner/refresh_v2/-/refresh_v2-1.0.3.har",

     "registryType": "ohpm"

   },
js 复制代码
+  "@abner/refresh_v2@^1.0.3": "@abner/refresh_v2@1.1.0",

  
   "packages": {

+  "@abner/refresh_v2@1.1.0": {

     "name": "@abner/refresh_v2",

+    "version": "1.1.0",

+    "integrity": "sha512-doLWKi0W0vnb459u+NKtpeBye+AY8VEQLVpLrd34HPfMZgm5gcH/0ANV1m09fTULlNk1Dfy+PpJdaa9p2RK2FQ==",

+    "resolved": "https://ohpm.openharmony.cn/ohpm/@abner/refresh_v2/-/refresh_v2-1.1.0.har",

     "registryType": "ohpm"

   },

十二: px & vp

vp Virtual Pixel 虚拟像素,会根据屏幕像素密度自动缩放,1vp = 1px / 像素密度,适合做响应式布局
px Physical Pixel 物理像素,屏幕上真实的像素点,不会自动缩放

在 ArkUI 中,当 paddingwidthheightmargin 等布局属性接收 number 类型时,默认单位就是 vp ,因此 10 等价于 10vp

js 复制代码
// 写法一:number 类型,默认单位 vp
.padding({ top: 10 })       // 等价于 10vp

// 写法二:string 类型,显式指定 vp
.padding({ top: '10vp' })   // 同样是 10vp

// 写法三:string 类型,显式指定 px
.padding({ top: '10px' })   // 10 物理像素,不会随屏幕密度缩放

// 写法四:string 类型,不指定单位,默认 vp
.padding({ top: '10' })     // 等价于 10vp
js 复制代码
// 获取布局避让遮挡的区域, 底部导航条高度 并缓存  这里获取的就是 px

// 避让区 导航类型
let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; 
// 获取避让区导航
let avoidArea = windowClass.getWindowAvoidArea(type);
// 获取到导航条区域的高度 单位 px
let bottomRectHeight = avoidArea.bottomRect.height; 
// 存储导航高度 
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
kotlin 复制代码
// 在组件中使用需要加上 px 否则会按照vp编译 产生偏差
.padding({ top: this.topRectHeight + 'px' }) //距离 顶部高度

十三 窗口全屏 & 避让区高度(状态栏/下导航) & 主题设置

js 复制代码
// 主题配置
export class AppColors implements CustomColors {
  // 1 文本主题颜色 包括font, input字体颜色
  fontPrimary = Color.Red;
  
  // 2 系统组件主题背景色 包括qrcode  (感觉有点鸡肋)
  backgroundPrimary: ResourceColor = $r('app.color.bg');
  
  // 3 文档没写啥组件生效 大概是获取颜色用吧
  compBackgroundPrimary: ResourceColor = $r('app.color.bg');
  
  // 光标主题颜色 包括inpuit光标
  brand: ResourceColor = $r('app.color.colorPrimary'); 
  
  // 使用$r,让一级警示色在深色和浅色模式下,设置为不同的颜色 
  warning: ResourceColor = $r('app.color.start_window_background');
}

// warning补充说明

/** 深浅模式不同颜色
 start_window_background 分别在
 resources/base/element/color.json, 
 resources/dark/element/color.json设置颜色 所以切换深浅色模式可以变换颜色
*/

/** warning主题配置生效的组件有
 TipsDialog 提示弹窗 -> (取消/确认 文本的颜色)
 AlertDialog 警告弹窗 -> (文本的颜色)    
 CustomContentDialog 自定义内容弹窗  -> (文本的颜色)
 Badge 徽标组件  -> (边框线颜色)
 Button 按钮组件 -> (背景颜色)
*/

export class AppTheme implements CustomTheme {
  colors?: CustomColors;

  constructor(colors: CustomColors) {
    this.colors = colors;
  }
}

const BlueColorsTheme = new AppTheme(new AppColors());


onWindowStageCreate(windowStage: window.WindowStage): void {

    // 获取应用主窗口
    let windowClass: window.Window = windowStage.getMainWindowSync();

    // 1. 设置窗口全屏
    
    let isLayoutFullScreen = true;
    
    windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => {
      console.info('Succeeded in setting the window layout to full-screen mode.');
    }).catch((err: BusinessError) => {
      console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
    });

    // 2. 获取避让遮挡的区域 
    // 2.1 下导航高度并缓存  
    
    let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 以导航条避让为例
    let avoidArea = windowClass.getWindowAvoidArea(type);
    let bottomRectHeight = avoidArea.bottomRect.height; // 获取到导航条区域的高度
    AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);

    // 2.2 状态栏高度并缓存  
    
    type = window.AvoidAreaType.TYPE_SYSTEM; // 以状态栏避让为例
    avoidArea = windowClass.getWindowAvoidArea(type);
    let topRectHeight = avoidArea.topRect.height; // 获取状态栏区域高度
    AppStorage.setOrCreate('topRectHeight', topRectHeight);

    // 2.3. 注册监听函数,动态获取避让区域数据(下导航 / 状态栏)
    // 当用户折叠/展开导航条、切换横竖屏等场景下,避让区域会发生变化,需要实时更新全局状态
    
    windowClass.on('avoidAreaChange', (data) => {
      if (data.type === window.AvoidAreaType.TYPE_SYSTEM) { // 状态栏
        let topRectHeight = data.area.topRect.height;
        AppStorage.setOrCreate('topRectHeight', topRectHeight);
      } else if (data.type == window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { // 下导航
        let bottomRectHeight = data.area.bottomRect.height;
        AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
      }
    });
    
    //3. 设置全局状态栏内容颜色, 可单独页面更改. 状态栏文字 字体
    
    windowClass.setWindowSystemBarProperties({
      statusBarContentColor: '#FFFFFF' // 白色
    });

    // 4. 设置应用自定义主题
    ThemeControl.setDefaultTheme(BlueColorsTheme)
  });
}

十四 配置应用 图标 & 名称

14.1 修改应用图标

js 复制代码
// AppScope/resources/base/media/layered_image,json 
// 修改图片地址
{
  "layered-image":
  {
    "background" : "$media:background",
    "foreground" : "$media:foreground_2"
  }
}

14.2 修改应用名称

js 复制代码
// 1 配置 $string:app_name
// AppScope/resources/base/element/string.json

{
  "string": [
    {
      "name": "app_name",
      "value": "testApp1"
    }
  ]
}


// 2 配置应用名称
// AppScope/app.json5

{
  "app": {
    "bundleName": "com.testapp.test1",
    "vendor": "example",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "buildVersion": "1",
    "icon": "$media:layered_image",
    "label": "$string:app_name" // 配置应用名称
  }
}

⚠️ module.json5 的优先级高于 app.json5,如果这里写错了会覆盖掉 app.json5 的配置

js 复制代码
// entry/src/main/module.json5

{
  "abilities": [
    {
      "label": "$string:EntryAbility_label"
    }
  ]
}

十五 应用配置信息介绍

js 复制代码
// AppScope/app.json5
{
  "app": {
    "bundleName": "com.testapp.test1", // 应用包名
    "vendor": "example", // 开发组织名称
    "versionCode": 1000000, // 上架的构建版本
    "versionName": "1.0.0", // 应用版本号
    "buildVersion": "1", // 没啥用
    "icon": "$media:layered_image", // 应用图标
    "label": "$string:app_name" // 应用名称
  }
}

十六 定义函数参数

js 复制代码
@Component
export struct comNavTitle {
  // 定义函数参数
  returnButtonClick: () => void = ()=>{ // ⚠️ 改成() => () 不行
    HMRouterMgr.pop()
  }
  
  build(){
   //......
  }
}

十七 启动背景颜色及图标修改

js 复制代码
// entry/src/main/module.json5

"abilities": [
  {
    "startWindowIcon": "$media:startIcon", // 启动图标
    "startWindowBackground": "$color:start_window_background", // 启动背景色
  }
]  
相关推荐
贾伟康3 小时前
【口算王|12】HarmonyOS ArkTS 启动页实战:处理 Splash 到训练首页的稳定切换
harmonyos·arkts·启动优化·uiability·windowstage
贾伟康6 小时前
【口算王|13】HarmonyOS ArkTS 应用启动链路实战:从 EntryAbility 到首屏加载保持窗口与路由稳定
harmonyos·arkts·arkui·应用启动·entryability
Java的搬运工2 天前
HarmonyOS ArkUI V2 实战:Schema 驱动表单、2in1 适配与实时通信
harmonyos·arkts·openharmony·harmonyos next·表单校验·arkui v2·2in1
贾伟康2 天前
【口算王|01】HarmonyOS ArkTS 口算题生成实战:按年级、运算类型和难度生成可控题目
算法·harmonyos·arkts·随机生成·口算题
贾伟康2 天前
【口算王|10】HarmonyOS ArkTS 语音报题实战:协调朗读、作答和页面生命周期
生命周期·harmonyos·arkts·语音交互·texttospeech
贾伟康2 天前
【口算王|08】HarmonyOS ArkTS 分类训练实战:让年级与运算分类参数保持一致
harmonyos·arkts·数据建模·路由参数·分类训练
贾伟康2 天前
【口算王|09】HarmonyOS ArkTS 学习统计实战:计算连续训练和正确率趋势
harmonyos·arkts·数据可视化·preferences·学习统计
贾伟康3 天前
【句匠|20】HarmonyOS ArkTS AppGallery 发布复查实战:核对包名、版本、设备、素材和离线声明
harmonyos·arkts·应用上架·appgallery·发布审核
贾伟康3 天前
【句匠|15】HarmonyOS ArkTS 本地状态持久化实战:让保存、删除和页面返回后的数据即时一致
harmonyos·arkts·数据持久化·appstorage·preferences