《探索 HarmonyOS NEXT(5.0):开启构建模块化项目架构奇幻之旅 ——第三方 ...

打印 上一主题 下一主题

主题 775|帖子 775|积分 2325

1、ef_rcp简介:是基于rcp封装的网络请求相关包.提供了rcp的上传,下载,post,get,cancel,delete,put等操作。
ef_rcp出处ef_rcp;
2、PullToRefresh简介:采用的装饰器有V1,V2,作者紧跟期间的潮流。功能上:实现垂直列表下拉刷新,上拉加载,横向列表左拉刷新,右拉加载等操作。
PullToRefresh出处PullToRefresh;
3、SmartDialog简介:鸿蒙版本的SmartDialog,优雅,极简的用法;非UI地域内利用,自界说Component;返回事件处理,优化的跨页面交互;多弹窗本领,多位置弹窗:上下左右中间;
定位弹窗:自动定位目的Component;极简用法的loading弹窗。
SmartDialog出处SmartDialog;
非常感谢大佬们出的库,方便我们开发,提高我们开发效率,更具体的先容和利用请看官方出处。
其它
RCP官网
RCP网络请求配置

1、增长BaseResponse。

  1. export class BaseResponse<T> {
  2.   //成功失败标识
  3.   private success: boolean;
  4.   //返回提示信息
  5.   private msg: string;
  6.   //响应编码
  7.   private code: string | number;
  8.   //返回数据
  9.   private data: T;
  10.   /**
  11.    * 构造函数
  12.    * @param success  是否成功标识
  13.    * @param msg   提示消息
  14.    * @param data  数据
  15.    */
  16.   constructor(success: boolean, msg: string, data: T, code: string | number) {
  17.     this.msg = msg;
  18.     this.success = success;
  19.     this.code = code;
  20.     this.data = data;
  21.   }
  22.   /**
  23.    * 创建空实例
  24.    * @returns
  25.    */
  26.   static create(): BaseResponse<string> {
  27.     let baseResponse = new BaseResponse<string>(true, '', '', 200);
  28.     return baseResponse;
  29.   }
  30.   /**
  31.    * 成功-只包含消息
  32.    * @param msg   提示消息
  33.    * @returns
  34.    */
  35.   static OK(msg: string): BaseResponse<string> {
  36.     let baseResponse = new BaseResponse<string>(true, msg, '', 200);
  37.     return baseResponse;
  38.   }
  39.   /**
  40.    * 成功-包含单行数据
  41.    * @param msg  提示消息
  42.    * @param data  单行数据
  43.    * @returns
  44.    */
  45.   static OKByData<T>(msg: string, data: T): BaseResponse<T> {
  46.     let dto = new BaseResponse<T>(true, msg, data, 200);
  47.     return dto;
  48.   }
  49.   /**
  50.    * 失败-包含提示消息
  51.    * @param msg 提示消息
  52.    * @returns
  53.    */
  54.   static Error(msg: string): BaseResponse<string> {
  55.     let dto = new BaseResponse<string>(false, msg, '', 400);
  56.     return dto;
  57.   }
  58.   /**
  59.    * 失败-包含单行数据
  60.    * @param msg 提示消息
  61.    * @param data 单行数据
  62.    * @returns
  63.    */
  64.   static ErrorByData<T>(msg: string, data: T): BaseResponse<T> {
  65.     let dto = new BaseResponse<T>(false, msg, data, 400);
  66.     return dto;
  67.   }
  68.   public setSuccess(success: boolean) {
  69.     this.success = success;
  70.   }
  71.   public getSuccess(): boolean {
  72.     return this.success;
  73.   }
  74.   public getCode(): string | number {
  75.     return this.code;
  76.   }
  77.   public setCode(code: string | number) {
  78.     this.code = code;
  79.   }
  80.   public getMsg(): string {
  81.     return this.msg;
  82.   }
  83.   public setMsg(msg: string) {
  84.     this.msg = msg;
  85.   }
  86.   public getData(): T {
  87.     return this.data;
  88.   }
  89.   public setData(data: T) {
  90.     this.data = data;
  91.   }
  92. }
复制代码
2、增长不同接口返回不同数据结构的响应内容拦截器,保持输出划一。

官方拦截器链接
2.1.思量几种常见数据返回的
  1. // {"code":200,"message":"success","data":{"isCheck":"0"}}
  2. // {"status":"1","msg":"success","result":{"data":{"ticket":"ST-2c2fd56bad7f49259edbb4b00ccc6cbe"}}}
复制代码
2.2.修改响应内容



  • 先获取响应效果
  1. const response = await next.handle(context);
复制代码


  • 把接口返回不同的code,msg,data转为划一。例子中code为200和0代表成功,可根据公司规定修改。
  • 思量几种常见数据返回的
  1.       // {"code":200,"message":"success","data":{"isCheck":"0"}}
  2.       // {"status":"1","msg":"success","result":{"data":{"ticket":"xxxxx"}}}
  3.       // {"data": ..., "errorCode": 0, "errorMsg": ""} errorCode = 0 代表执行成功.errorCode = -1001 代表登录失效,需要重新登录
复制代码
  1. //转换成object
  2.       let result = response.toJSON();
  3. //考虑几种常见数据返回的
  4.       // {"code":200,"message":"success","data":{"isCheck":"0"}}
  5.       // {"status":"1","msg":"success","result":{"data":{"ticket":"ST-2c2fd56bad7f49259edbb4b00ccc6cbe"}}}
  6.       // {"data": ..., "errorCode": 0, "errorMsg": ""} errorCode = 0 代表执行成功.errorCode = -1001 代表登录失效,需要重新登录
  7.       //1.成功失败标识
  8.       let success: boolean = true;
  9.       //2.返回的消息提示
  10.       let message: string = '';
  11.       //3.返回的数据
  12.       let data: Record<string, Object> = {};
  13.       //4.返回请求状态码
  14.       let code = response.statusCode + '';
  15.       if (result) {
  16.         Object.entries(result).forEach((item: object) => {
  17.           if (["errorCode", "code", "status"].includes(String(item[0]))) {
  18.             code = String(item[1])
  19.             success = disposeCode(String(item[1]));
  20.           }
  21.           if (["errorMsg", "message", "msg"].includes(String(item[0]))) {
  22.             message = String(item[1]);
  23.           }
  24.           if (["data", "result"].includes(String(item[0]))) {
  25.             data = item[1];
  26.           }
  27.         })
  28.       }
  29.       // HTTP status code
  30.       if (response.statusCode != 200) {
  31.         success = false;
  32.         message = (response.toString() as string) ? response.toString() as string : "网络错误";
  33.       }
复制代码


  • 成功失败标识用success表示。
  1. if (["code", "status"].includes(String(item[0]))) {
  2.           code = String(item[1])
  3.           success = disposeCode(String(item[1]));
  4.         }
复制代码


  • disposeCode的作用,处理不同接口返回的码
  1. /** 处理不同接口返回的码.errorCode = 0 || code==200 || status==1 为成功 */
  2. export function disposeCode(s: string): boolean {
  3. let isSuccess: boolean = false;
  4. if ("0" == s || "200" == s || "1" == s) {
  5. isSuccess = true;
  6. }
  7. return isSuccess;
  8. }
复制代码


  • 返回统一格式
  1.     let baseResponse = new BaseResponse(success, disposeMsg(code, message), data, code);
复制代码


  • disposeMsg的作用,表示处理信息,比如针对于特定的code码,返回指定的msg。
  1. /** 处理信息 */
  2. export function disposeMsg(code: string, msg: string): string {
  3.   let message = "";
  4.   switch (code) {
  5.     case '-1001':
  6.     case '401':
  7.       message = "登陆信息过期,请重新登陆";
  8.       break;
  9.     case '403':
  10.       message = "账号异常,请联系客服";
  11.       break;
  12.     case '429':
  13.       message = "您的操作过于频繁,请稍后再试!";
  14.       break;
  15.     case '500':
  16.       message = "服务器错误(500)";
  17.       break;
  18.     default:
  19.       message = `${msg}`;
  20.   }
  21.   const errorCodes = ['401', '403', '429', '500'];
  22.   if (errorCodes.includes(code)) {
  23.     //吐司
  24.     ToastUtil.showToast(message);
  25.   }
  26.   return message;
  27. }
复制代码


  • 修改响应后,给rcp.Response传过去。
  1.       //对响应修改
  2.       const toReturn: rcp.Response = {
  3.         request: response.request,
  4.         statusCode: response.statusCode,
  5.         headers: response.headers,
  6.         effectiveUrl: response.effectiveUrl,
  7.         body: response.body,
  8.         downloadedTo: response.downloadedTo,
  9.         timeInfo: response.timeInfo,
  10.         httpVersion: response.httpVersion,
  11.         reasonPhrase: response.reasonPhrase,
  12.         toString: () => response.toString(),
  13.         toJSON: () => baseResponse
  14.       };
  15.       return toReturn;
复制代码
3、初始化参数配置,在EntryAbility的onWindowStageCreate写

  1.     // if(运行环境===debug){
  2.    efRcp
  3.      .setBaseURL("https://www.wanandroid.com") //设置请求路径
  4.      .enableLogInterceptor()//设置为false即可关闭
  5.      .setLoadingContent('正在加载中...')//更改loading文本
  6.      .convertError(true)//表示如果response.toJSON()异常时将响应字符串返回,false则表示值返回异常提醒而不返回结果
  7.      .addCommonHeaders({//设置公共头
  8.        "version": `V1.0.0`
  9.      })// .setLoadingImg(wrapBuilder(loadingImg)) //设置loading为gif图片
  10.      .addCustomInterceptors([new ResponseInterceptor()])
  11.      .addSysCodeEvent({//添加统一系统框架级别编码处理逻辑,如超时等
  12.        listener: (code: number) => {
  13.          // Log.d('---------addSysCodeEvent监听事件-----' + code)
  14.          switch (code) {
  15.          case -1001:
  16.            case 401:
  17.              console.log(`xxx : ---跳转登录页面,清空一些数据等`)
  18.              //跳转登录页面,清空一些数据等
  19.              // ZRouter.replacePathByName('LoginPage')
  20.              break;
  21.          }
  22.        }
  23.      })//创建session对象,需要再设置为一系列操作后再调用,否则设置不生效,可在特殊情况处设置其他操作后重新创建session
  24.      .create()//获取统一的session对象,必须在create后调用 .设置了全局的配置比如拦截器  超时时间  session本身的配置 ,需要再次create
  25.      .builder();
  26.    // }
复制代码
4、如何利用,更多具体内容可以参考ef_rcp作者的主页



  • post请求为例,例子在 TestNetView 页面
  1. //登录
  2.           let login = await PhoneService.login({
  3.             'username': '鸿蒙',
  4.             'password': '5.0'
  5.           })
  6.           console.log('xxxlogin--' + '' + json.stringify(login))
  7.           if (login.data?.getSuccess()) {
  8.             this.message = json.stringify(login.data.getData())
  9.             console.log('xxxxxdata参数--' + '' + json.stringify(login.data.getData()))
  10.           } else {
  11.             console.log('xxx--' + login.data?.getMsg())
  12.             ToastUtil.showToast(login.data?.getMsg())
  13.           }
  14.          
  15. PhoneService类
  16. export class PhoneService {
  17.   static login(query: Record<string, Object>): Promise<EfRcpResponse<BaseResponse<object>>> {
  18.     return efRcpClientApi.post<BaseResponse<object>>({
  19.       url: 'user/login',
  20.       query: query,
  21.       loadingTxt: '正在登录中...',
  22.       loading: false
  23.     });
  24.   }
  25. }
复制代码

5、自带的loading( 图一 ) 假如不符合可以自界说一个builder,参考下面的弹窗设置。




  • 设置自界说loading样式和内容
    .setLoadingBuilder(wrapBuilder(loadingNetView))
  1. /** 目前网络请求不支持传loading文字 */
  2. @Builder
  3. function loadingNetView() {
  4.   Column() {
  5.     loadingBuilder()
  6.   }
  7.   .border({
  8.     width: 1,
  9.     radius: 8,
  10.     color: $r('app.color.color_F0F0F0')
  11.   })
  12. }
  13. @Builder
  14. function loadingView(args: ResourceStr = '正在加载中...') {
  15.   loadingBuilder(args)
  16. }
  17. @Builder
  18. function loadingBuilder(args?: ResourceStr) {
  19.   Column() {
  20.     Image($r('app.media.loading_refresh')).width(50).height(50)
  21.     Text(args ? args : '正在加载中...')
  22.       .fontSize(11)
  23.       .fontColor($r('app.color.color_222222'))
  24.       .margin({ top: 11 })
  25.       .maxLines(1)
  26.       .textOverflow({ overflow: TextOverflow.Ellipsis })
  27.   }
  28.   .width(120)
  29.   .height(120)
  30.   .justifyContent(FlexAlign.Center)
  31.   .backgroundColor(Color.White)
  32.   .borderRadius(12)
  33. }
复制代码

PullToRefresh上下拉刷新配置,采用V2装饰器版本

1、下载安装,目前版本是 “^2.0.1”

  1. ohpm install @zhongrui/pull_to_refresh_v2
复制代码
2、每个项目的上下拉刷新头部,尾部都不一样,以是我这里采用了个性化定制,请利用RefreshLayout



  • 上下拉刷新例子–>TestRefreshView
  1. @Preview
  2. @ComponentV2
  3. export struct TestRefreshView {}
复制代码


  • 自界说刷新头部

  1.   @Builder
  2.   defHeaderView() {
  3.     Stack({ alignContent: Alignment.Center }) {
  4.       if (this.pullDown?.status == PullStatus.PullDown || this.pullDown?.status == PullStatus.Refresh || this.pullDown?.status == PullStatus.PreRefresh) {
  5.         Row() {
  6.           Image($r("app.media.loading_refresh")).width(50).height(40)
  7.         }.width('100%')
  8.         .height(50)
  9.         .justifyContent(FlexAlign.Center)
  10.       } else if (this.pullDown?.status == PullStatus.RefreshSuccess) {
  11.         // Text("刷新成功").textExtend()
  12.       } else if (this.pullDown?.status == PullStatus.RefreshError) {
  13.         Text("刷新失败,请重新尝试").textExtend()
  14.       }
  15.     }.height(50).width("100%")
  16.   }
复制代码


  • 自界说刷新尾部

  1.   /** 自定义刷新尾部 */
  2.   @Builder
  3.   defFooterView() {
  4.     Stack({ alignContent: Alignment.Center }) {
  5.       if (this.pullDown?.status == PullStatus.PullUp || this.pullDown?.status == PullStatus.Load || this.pullDown?.status == PullStatus.PreLoad) {
  6.         Row() {
  7.           Image($r("app.media.loading_refresh"))
  8.             .width(24)
  9.             .height(24)
  10.         }.width('100%')
  11.         .height(60)
  12.         .justifyContent(FlexAlign.Center)
  13.       } else if (this.pullDown?.status == PullStatus.LoadSuccess) {
  14.         // Text("加载完成").textExtend()
  15.       } else if (this.pullDown?.status == PullStatus.LoadError) {
  16.         Text('加载失败,请重新尝试').textExtend()
  17.       }
  18.     }.height(50).width("100%")
  19.   }
复制代码


  • 内容视图

  1.   /** 内容视图 */
  2.   @Builder
  3.   _ContentView() {
  4.     Text("contentView:()=>{your @Builder View}")
  5.   }
复制代码


  • loading视图

  1.   /** loading视图 */
  2.   @Builder
  3.   loadingView() {
  4.     this.layout($r('app.media.loading_refresh'), '正在加载...')
  5.   }
复制代码


  • 空视图

  1.   /** 空视图 */
  2.   @Builder
  3.   _EmptyView() {
  4.     this.layout($r('app.media.nodata'), '暂无数据')
  5.   }
复制代码


  • 错误视图

  1.   /** 错误视图 */
  2.   @Builder
  3.   _ErrorView() {
  4.     this.layout($r('app.media.no_network'), '暂无网络,请重新尝试')
  5.   }
复制代码


  • 视图公用
  1. /** 视图公用 */
  2.   @Builder
  3.   layout(src: ResourceStr, text: ResourceStr) {
  4.     Column() {
  5.       Image(src).width(48).height(48)
  6.       Text(text).fontSize(12).fontColor($r('app.color.color_999999')).padding(8)
  7.     }.width(CommonConst.FULL_PARENT)
  8.     .height(CommonConst.FULL_PARENT)
  9.     .justifyContent(FlexAlign.Center)
  10.   }
复制代码


  • 底部暂无更多(目前只能往上拉才能看到,假如不上拉也能看到,那就自界说一个Item放到最下面)。

  1.   /**
  2.    * 暂无更多
  3.    * @param isV 是否竖向
  4.    */
  5.   @Builder
  6.   defFooterNoMoreView(isV: boolean) {
  7.     Text('没有更多数据了')
  8.       .textAlign(TextAlign.Center)
  9.       .height(isV ? 50 : CommonConst.FULL_PARENT)
  10.       .width(isV ? CommonConst.FULL_PARENT : 50)
  11.       .fontSize(14)
  12.       .fontColor($r('app.color.color_999999'))
  13.   }
  14.   private isVerticalLayout(): boolean {
  15.     return (this.config.isVertical || this.config.horizontalMode == 1 || this.config.horizontalMode == 2)
  16.   }
  17. }
复制代码


  • 默认带弹性效果的列表必要关闭弹性滑动
  1. .edgeEffect(EdgeEffect.None)
复制代码


  • BasicDataSource,配合LazyForEach利用,数据太多的话建议用LazyForEach;后期可以看看(Repeat:子组件复用)
  1. 源代码请看项目中,模块uicomponents /src/main/ets/components/refresh/BasicDataSource
复制代码
3、封装请求返回的数据,更加简洁



  • 如何利用
  1.   /** 请求接口 */
  2.   async loadData() {
  3.     let data: Array<string> = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"]
  4.     // let data:string[] = []// 空数据
  5.     this.dataSource.pageRefresh(true, this.pageNum, data.length, data, this.controller,
  6.       (pages: number) => {
  7.         this.pageNum = pages
  8.       })
  9.   }
复制代码
  1. /**
  2.    * 列表页数 处理
  3.    * @param success  成功失败标识
  4.    * @param page     页数
  5.    * @param total    总条数
  6.    * @param data     数据
  7.    * @param controller RefreshController
  8.    * @param pageNums 返回的page
  9.    */
  10.   public pageRefresh(success: boolean, page: number, total: number, data: Array<T>, controller: RefreshController, pageNums: (pages: number) => void) {
  11.     if (success) {
  12.       if (page == 1) {
  13.         this.setNewData(data)
  14.         controller.refreshSuccess()
  15.         pageNums(2)
  16.         if (this.totalCount() == 0) {
  17.           controller.viewEmpty()
  18.         }
  19.       } else {
  20.         this.addAllData(data)
  21.         controller.loadSuccess()
  22.         pageNums(data.length == 0 ? page : (page + 1))
  23.       }
  24.       // 是否还有更多
  25.       setTimeout(() => {
  26.         controller.hasMore(this.totalCount() < total /*|| !(data.length < 10)*/)
  27.       }, 800) //处理暂无更多数据视图和列表同时显示出来
  28.     } else {
  29.       if (controller.getStatus() == PullStatus.Refresh) {
  30.         controller.refreshError()
  31.       } else {
  32.         controller.loadError()
  33.       }
  34.       if (page == 1) {
  35.         controller.viewError()
  36.       }
  37.     }
  38.   }
复制代码
SmartDialog弹窗配置



  • 更多细节请参考大佬写的
安装

  1. ohpm install ohos_smart_dialog
复制代码

全局设置一个loadding样式



  • Index页面
  1. OhosSmartDialog({ loadingBuilder: customLoading })
复制代码
  1. /** 自定义页面弹窗 */
  2. @Builder
  3. function customLoading(args: ResourceStr = '正在加载中...') {
  4.   Column() {
  5.     Image($r('app.media.loading_refresh')).width(50).height(50)
  6.     Text(args)
  7.       .fontSize(11)
  8.       .fontColor($r('app.color.color_222222'))
  9.       .margin({ top: 11 })
  10.       .maxLines(1)
  11.       .textOverflow({ overflow: TextOverflow.Ellipsis })
  12.   }
  13.   .width(120)
  14.   .height(120)
  15.   .justifyContent(FlexAlign.Center)
  16.   .backgroundColor(Color.White)
  17.   .borderRadius(12)
  18. }
复制代码



  • 路由子页面一定要加,返回事件监听
  1. .onBackPressed(OhosSmartDialog.onBackPressed())
复制代码
以往系列文章


  • 《探索 HarmonyOS NEXT(5.0):开启构建模块化项目架构奇幻之旅 —— 模块化基础篇》
  • 《探索 HarmonyOS NEXT(5.0):开启构建模块化项目架构奇幻之旅 —— 构建基础特性层》
  • 《探索 HarmonyOS NEXT(5.0):开启构建模块化项目架构奇幻之旅 —— 构建公共本领层》
  • 《探索 HarmonyOS NEXT(5.0):开启构建模块化项目架构奇幻之旅 —— Tabs底部导航栏》
  • 《探索 HarmonyOS NEXT (5.0):开启构建模块化项目架构奇幻之旅 —— 动态路由 ZRouter:引领高效模块通讯的聪明中枢》
若本文对您稍有帮助,诚望您不吝点赞,多谢。
有爱好的同学可以点击查看源码



  • gitee:https://gitee.com/jiaojiaoone/explore-harmony-next.git
  • github:https://github.com/JasonYinH/ExploreHarmonyNext.git
欢迎加我微信一起交换:+V:yinshiyuba


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

灌篮少年

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表