arkts- 8 三方库 hmrouter/mmkv/axios/refresh_v2/harmony-dialog

118 阅读5分钟

OpenHarmony三方库中心仓

一 @hadss/hmrouter & 导航

1.1 路由配置

@hadss/hmrouter地址

==>步骤1 安装

ohpm install @hadss/hmrouter

==>步骤2 依赖配置 插件配置

2.1 依赖配置

修改工程根目录下的hvigor/hvigor-config.json5 文件,加入路由编译插件

"dependencies": {
  "@hadss/hmrouter-plugin": "^1.2.4"  // 保持和 oh-package.json5中安装的版本一致
},

2.2 插件配置

修改工程根目录下的hvigorfile.ts,使用路由编译插件

⚠️⚠️ 特别注意 !!

  • 配置最下面的hvigorfile.ts 工程级别
  • entry模块下也有个hvigorfile.ts不要配置错误 entry/hvigorfile.ts
import { appTasks } from '@ohos/hvigor-ohos-plugin';
import { appPlugin } from "@hadss/hmrouter-plugin";

export default {
  system: appTasks,
  plugins: [appPlugin({ ignoreModuleNames: [ /** 不需要扫描的模块 **/ ] })]
  // 别扫描 我自己手动处理
};

==>步骤3 初始化路由框架

在 UIAbility 或者启动框架 AppStartup 中初始化路由框架

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  
    // 日志开启需在init之前调用,否则会丢失初始化日志
    HMRouterMgr.openLog("INFO")
    HMRouterMgr.init({
      context: this.context
    })
  }
}

==>步骤4 定义路由入口

HMRouter 依赖系统 Navigation 能力,所以必须在页面中定义一个 HMNavigation 容器


# 1 在 ThirdPageOfNav 页, 定义导航入口页 NavHomePage

# 2 NavOtherPage 页 跳转 NavOtherPage 页

# 3 NavOtherPage 返回 NavOtherPage

截屏2026-08-21 10.24.09.png


// 1. thirdPageOfNav 页面中配置导航

// NavHomePage 为入口页面
// navigationId  为 'mainNavigation'
// 配置转场动画
// 配置 隐藏工具栏及标题

import { HMDefaultGlobalAnimator, HMNavigation } from '@hadss/hmrouter';
import { AttributeUpdater } from '@kit.ArkUI';

@Entry
@Component
struct thirdPageOfNav {
  modifier: NavModifier = new NavModifier();

  build() {
    Column() {
      Text('thirdPageOfNav').fontSize(30)
      HMNavigation({
        navigationId: 'mainNavigation', // 路由栈唯一标识
        homePageUrl: 'NavHomePage', // 指定入口页 为 NavHomePage页
        options: {
          standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR, // 标准转场动画
          dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,     // 弹窗转场动画
          modifier: this.modifier            // 导航属性修饰器
        }
      })
    }
    .backgroundColor(Color.Red)
    .width('100%')
    .height('100%')
  }
}

// 通过 AttributeUpdater 配置 Navigation 属性
class NavModifier extends AttributeUpdater<NavigationAttribute> {
  initializeModifier(instance: NavigationAttribute): void {
    instance.mode(NavigationMode.Stack);  // 单栏模式
    instance.navBarWidth('100%');
    // instance.hideTitleBar(true);          // 隐藏标题栏
    // instance.hideToolBar(true);           // 隐藏工具栏
  }
}

// 2. NavHomePage 为入口页面

// 注意 
// 页面添加 export
// 定义标签 'NavHomePage'

import { HMRouter, HMRouterMgr,HMPopInfo } from '@hadss/hmrouter';


// 使用 @HMRouter 标签定义页面,绑定拦截器、生命周期及自定义转场动画
@HMRouter({
  pageUrl: 'NavHomePage', // 标签定义页面
  // interceptor: ['PageInterceptor'], // 绑定拦截器
  // lifecycle: 'pageLifecycle', // 生命周期
  // animator: 'pageAnimator' // 自定义转场动画
})

@Component
export struct NavHomePage{
  private param: DetailParam = new DetailParam()
  @State receivedResult: string = '暂无返回数据'

  aboutToAppear(): void {
    // 获取路由传递的参数
    const currentParam = HMRouterMgr.getCurrentParam() as DetailParam
    if (currentParam !== null) {
      this.param = currentParam
    }
  }

  build() {
    Column() {
      Text('NavHomePage') .fontSize(30)
      Text('获取参数:' + '\n'+ this.receivedResult).fontSize(15).backgroundColor(Color.Green).margin({top:30})
      Button('跳转到其他页')
        .onClick(() => {
          // 跳转并传参
          HMRouterMgr.push({
            navigationId: 'mainNavigation', // 导航id
            pageUrl: 'NavOtherPage', // 跳转到目标页面
            param: {
              id: 111,
              name: 'NavHomePage'
            } // 携带参数
          },{
            onResult: (popInfo: HMPopInfo) => { // 跳转到新页面,返回时的回调
              const res = popInfo.result as DetailParam
              if (res !== null && res !== undefined) {
                this.receivedResult = String(res.id) + res.name
                console.log(this.receivedResult);
              }
              console.info(`来源页面:${popInfo.srcPageInfo.name}`) // 获取返回来源页面名称
            }
          })
        })
    }
    .width('100%') .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}



// 3. NavOtherPage 当前页

// 注意 
// 页面添加 export
// 定义标签 'NavOtherPage'


@HMRouter({ pageUrl: 'NavOtherPage' })

@Component
export struct NavOtherPage {
  private param: DetailParam = new DetailParam()

  aboutToAppear(): void {
    // 获取外传进来的参数
    const currentParam = HMRouterMgr.getCurrentParam() as DetailParam
    if (currentParam !== null) {
      this.param = currentParam
    }
  }
  build() {
    Column() {
      Text('NavOtherPage') .fontSize(30)
      Text(`获取参数为: - ID: ${this.param.id}, 名称: ${this.param.name}`).backgroundColor(Color.Green)
        .fontSize(20)
      Button('返回上一页')
        .onClick(() => {
          HMRouterMgr.pop({ navigationId: 'mainNavigation' })
        })
      Button('带参数返回')
        .onClick(() => {
          HMRouterMgr.pop({
            navigationId: 'mainNavigation',
            param: {
              id: 222,
              name: 'NavOtherPage'
            }
          })
        })
    }
    .width('100%') .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

// 定义参数模型
class DetailParam {
  id: number = 0
  name: string = ''
}

1.2 页面显示/隐藏监听


// 监听导航栈内 某页面的 页面显示/隐藏 声明周期

// 修改状态栏字体颜色

import { HMLifecycle, HMLifecycleContext, IHMLifecycle } from '@hadss/hmrouter';
import { common } from '@kit.AbilityKit';

// 声明一个名为 LoginLifecycle 的生命周期监听器
@HMLifecycle({ lifecycleName: 'LoginLifecycle' })
export class LoginLifecycle implements IHMLifecycle {
  onShown(ctx: HMLifecycleContext): void { // 进入界面
   // 修改状态栏文本 颜色为黑色
    const uiContext = ctx.uiContext.getHostContext() as common.UIAbilityContext
    uiContext.windowStage.getMainWindowSync().setWindowSystemBarProperties({
      statusBarContentColor: '#000000'
    });
  }
  // 修改状态栏文本 颜色为白色
  onHidden(ctx: HMLifecycleContext): void { // 离开界面
    const uiContext = ctx.uiContext.getHostContext() as common.UIAbilityContext
    uiContext.windowStage.getMainWindowSync().setWindowSystemBarProperties({
      statusBarContentColor: '#FFFFFF'
    });
  }
}


// LOGIN_PAGE页面 添加页面显示/消失监视器, 配置如下

 @HMRouter({ pageUrl: PageConstants.LOGIN_PAGE, lifecycle: 'LoginLifecycle' }) 

1.3 全局侧滑监听 & web页侧滑监听


// 1 全局页面侧滑  到退出应用

import { HMLifecycle, HMLifecycleContext, IHMLifecycle } from '@hadss/hmrouter';
import showToast from '../../utils/ToastUtils';

@HMLifecycle({ lifecycleName: 'ExitAppLifecycle' })
export class ExitAppLifecycle implements IHMLifecycle {
  private lastTime: number = 0;
  // 不调用~~~
  onBackPressed(ctx: HMLifecycleContext): boolean { //侧滑返回 非页面内
    let time = new Date().getTime(); // 获取当前时间
    if (time - this.lastTime > 1000) { // 两次点击 间隔大于1s
      this.lastTime = time; // 记录本次
      showToast('再按一次退出', ctx.uiContext, 1000) // toast按需更换
      return true;
    } else {
      return false;
    }
  }
}

// 2.1 监听web页面侧滑返回

aboutToAppear(): void { 
    // 获取当前页面生命周期托管者
    const lifecycleOwner = HMRouterMgr.getCurrentLifecycleOwner()
    if (lifecycleOwner) {
      // 添加页面显示观察者 监听侧滑返回
      lifecycleOwner.addObserver(HMLifecycleState.onBackPressed, (ctx) => { 
        if (this.webController.accessBackward()) { // 有访问记录
          this.webController.backward() // 后退
          return true
        }
        return false
      });
    }
    // onBackPressed: 手机实体按键
    // onBackClick: 导航返回键
}

// 2.2 页面上导航 返回键
onBackClick: () => {
  if (this.webController.accessBackward()) { // 如果有历史记录
    this.webController.backward() // web 内部后退
  } else {
    HMRouterMgr.pop(); // web  退出当前
  }
}


// MainPage 页面添加侧滑退出监听, 配置如下
@HMRouter({ pageUrl: 'MainPage', lifecycle: 'ExitAppLifecycle' })

1.4 模态窗口设置

// 配置模态动画

// 定义全局模态动画:从底部向上滑入,无缩放,不透明
const bottomSlideDialogAnimator: IHMAnimator.Effect = new IHMAnimator.Effect({
  direction: IHMAnimator.Direction.BOTTOM_TO_TOP,  // ← 从底部向上
  opacity: { opacity: 1 },                          // ← 不透明(无渐变)
  scale: { x: 1, y: 1 }                             // ← 无缩放
});

@Entry
@Component
struct Index {
  modifier: NavModifier = new NavModifier();
  build() {
    Column() {
      HMNavigation({
        navigationId: 'mainNavigation', // 路由栈唯一标识
        homePageUrl: 'GuidePage', // 指定入口页
        options: {
          standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR, // push转场动画
          // dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,     // 模态转场动画
          dialogAnimator: bottomSlideDialogAnimator,     // 模态转场动画(自定义)
          modifier: this.modifier            // 导航属性修饰器
        }
      })
    }
    .backgroundColor($r('app.color.app_Theme_gray'))
    .width('100%')
    .height('100%')
  }
}

// 登录页 配置模态方式进场

@HMRouter({ pageUrl: 'LoginPage', lifecycle: 'LoginLifecycle',dialog: true}) // 标签定义页面

二 @tencent/mmkv & 缓存

  • 对标 系统的Preferences
  • 为同步存储
    ohpm install @tencent/mmkv

// 1 首先需要UIAbility 中注册

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  
  // 获取应用全局上下文(Application Context)
  let appCtx = this.context.getApplicationContext();

  //初始化MMKV
  let mmkvRootDir = MMKV.initialize(appCtx);
  console.info('mmkv rootDir: ', mmkvRootDir);
  
  }


import { MMKV } from '@tencent/mmkv'

// 获取默认实例
const mmkv = MMKV.defaultMMKV()
// 等价于 const defaultMMKV = MMKV.mmkvWithID('mmkv.default')

// 写入
mmkv.encodeBool('isLogin', true)
mmkv.encodeString('userName', '张三')
mmkv.encodeNumber('userId', 1001)

// 读取
let isLogin: boolean = mmkv.decodeBool('isLogin', false)
let userName: string = mmkv.decodeString('userName', '')
let userId: number = mmkv.decodeNumber('userId', 0)

// 删除
mmkv.removeValueForKey('userName')

// 清空
mmkv.clearAll()

import { MMKV } from '@tencent/mmkv'

// 指定 mmapID 创建独立实例,数据互不干扰
const userMMKV = MMKV.mmkvWithID('user_store')
const settingMMKV = MMKV.mmkvWithID('setting_store')

userMMKV.encodeString('token', 'abc123')
settingMMKV.encodeBool('notifyEnabled', true)

// 各实例数据独立存储
let token = userMMKV.decodeString('token', '')
let notify = settingMMKV.decodeBool('notifyEnabled', false)

三 @ohos/axios & 网络请求

ohpm install @ohos/axios 

// 添加网络权限
// entry/src/main/module.json5

"requestPermissions": [{
  'name': 'ohos permission.INTERNET'
}],
import axios, { AxiosResponse } from '@ohos/axios'

axios.get(bannerPath)
  .then((res: AxiosResponse<BannerData>) => {
    if ( res.data.data &&  res.data.data.length >0) { // 注意 res.data 这tm才是原始数据, 三方库在原始数据外又包了一层
      this.list = res.data.data
    }
    console.log('----->' + JSON.stringify(this.list))
  })

// 框架请求全数据 网络请求响应Response:

{
  "data": {
      "data": [
          {
            "desc": "我们支持订阅啦~",
          "id": 30,
          "imagePath": "https://www.wanandroid.com/blogimgs/42da12d8-de56-4439-b40c-eab66c227a4b.png",
          "isVisible": 1,
          "order": 2,
          "title": "我们支持订阅啦~",
          "type": 0,
          "url": "https://www.wanandroid.com/blog/show/3352"
          }
          //...做了删减
      ],
      "errorCode": 0,
      "errorMsg": ""
   }, 
   // ⚠️ 注意 'data':{} // {} 为真实数据
   
  "status": 200, // 系统返回 
  "statusText": "",
  "headers": {
  "cache-control": "private",
  "connection": "close",
  "content-type": "application/json;charset=UTF-8",
  "date": "Wed, 26 Aug 2026 04:47:22 GMT",
  "expires": "Thu, 01 Jan 1970 08:00:00 CST",
  "server": "Apache-Coyote/1.1",
  "transfer-encoding": "chunked",
  "set-cookie": "JSESSIONID=2FD6A009659F9DA513653D39FFF21054; Path=/; Secure; HttpOnly"
  },
  "config": {
      "transitional": {
        "silentJSONParsing": true,
        "forcedJSONParsing": true,
        "clarifyTimeoutError": false
  },
  "adapter": [
    "ohos"
  ],
  "transformRequest": [
    null
  ],
  "transformResponse": [
    null
  ],
  "timeout": 0,
  "xsrfCookieName": "XSRF-TOKEN",
  "xsrfHeaderName": "X-XSRF-TOKEN",
  "maxContentLength": -1,
  "maxBodyLength": -1,
  "env": {
    "Blob": null
  },
  "headers": {
    "Accept": "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "Cookie": ""
  },
  "connectTimeout": 30000,
  "readTimeout": 10000,
  "checkResultCode": true,
  "interceptorHooks": {},
  "url": "https://www.wanandroid.com/banner/json",
  "method": "get"
},
  "request": {},
  "performanceTiming": {
  "dnsTiming": 0.138,
  "firstReceiveTiming": 1033.164,
  "firstSendTiming": 989.111,
  "redirectTiming": 0,
  "responseBodyTiming": 1034.057,
  "responseHeaderTiming": 1034.054,
  "tcpTiming": 49.778,
  "tlsTiming": 989.074,
  "totalFinishTiming": 1034.414,
  "totalTiming": 1036.889
}
}

官方定义HTTP响应码

// 框架外面包装了一层 data: 

// 这是后台的接口
{
  "data": [
      {
        "desc": "我们支持订阅啦~",
      "id": 30,
      "imagePath": "https://www.wanandroid.com/blogimgs/42da12d8-de56-4439-b40c-eab66c227a4b.png",
      "isVisible": 1,
      "order": 2,
      "title": "我们支持订阅啦~",
      "type": 0,
      "url": "https://www.wanandroid.com/blog/show/3352"
      }
      //...做了删减
  ],
  "errorCode": 0,
  "errorMsg": ""
}

四 @abner/refresh_v2 & 刷新/加载

ohpm install @abner/refresh_v2

import axiosClient from '../network/AxiosRequest'
import { AxiosHeaders } from '@ohos/axios'
import { ListView } from '@abner/refresh_v2';
import { RefreshController, RefreshDataSource } from "@abner/refresh_v2";


controller: RefreshController = new RefreshController() //刷新控制器,声明全局变量
dataSource: RefreshDataSource = new RefreshDataSource() //数据懒加载操作对象,执行数据增删改查

// 网络请求 -- 下拉刷新
refreshRequest(isRefresh: boolean = false){
  this.pageIndex = 0
  axiosClient.get<BaseBean<BaseListBean<ArticleBean[]>>>({
    url: `${baseurl}article/list/${this.pageIndex}/json?cid=${this.cid}`,
    headers: new AxiosHeaders({ 'Cookie': ''}),
    showLoading: true
  }).then((res)=>{
    if ( res.data.datas &&  res.data.datas.length >0) {
      this.list = res.data.datas
      this.dataSource.initData(this.list)
    }
    if (isRefresh) {
      this.controller.finishRefresh()
    }
  })
    .catch((error: BusinessError)=>{
      if (isRefresh) {
        this.controller.finishRefresh()
      }
    })
}
// 网络请求 -- 上拉下载
loadMoreRequest() {
  this.pageIndex++
  axiosClient.get<BaseBean<BaseListBean<ArticleBean[]>>>({
    url: `${baseurl}article/list/${this.pageIndex}/json?cid=${this.cid}`,
    headers: new AxiosHeaders({ 'Cookie': ''}),
    showLoading: true
  }).then((res)=>{
    if ( res.data.datas &&  res.data.datas.length >0) {
      this.list = res.data.datas
      this.dataSource.pushDataArray(this.list);
    }
    this.controller.finishLoadMore() // 停止加载动画
  })
    .catch((error: BusinessError)=>{
      this.pageIndex--
      this.controller.finishLoadMore() // // 停止加载动画
    })
}

build() {
  Column() {
    ListView({
      lazyDataSource: this.dataSource, // 数据源
      itemLayout:(item, index) => {this.itemCell(item as ArticleBean,index)}, // item
      controller: this.controller, // 控制器
      enableLoadMore: this.loadMore, // 允许下拉刷新
      onRefresh: ()=>{
        this.refreshRequest(true)
      },
      onLoadMore: ()=>{
        this.loadMoreRequest()
      }
    })
  }
  .backgroundColor('#F5F5F5')
  .size({width:'100%',height:'100%'})
}

五 @pura/harmony-dialog

"@pura/harmony-dialog": "^1.1.8",

三方库中心仓