从网络获取数据

Web组件的使用
 

概述

相信大家都遇到过这样的场景,有时候我们点击应用的页面,会跳转到一个类似浏览器加载的页面,加载完成后,才显示这个页面的具体内容,这个加载和显示网页的过程通常都是浏览器的任务。

ArkUI为我们提供了Web组件来加载网页,借助它我们就相当于在自己的应用程序里嵌入一个浏览器,从而非常轻松地展示各种各样的网页。

本文将为您介绍Web组件一些常用API的使用。

2 加载网页

加载在线网页

Web组件的使用非常简单,只需要在Page目录下的ArkTS文件中创建一个Web组件,传入两个参数就可以了。其中src指定引用的网页路径,controller为组件的控制器,通过controller绑定Web组件,用于实现对Web组件的控制。

// xxx.ets
@Entry
@Component
struct WebComponent {
  controller: WebController = new WebController();
  build() {
    Column() {
      Web({ src: 'https://developer.harmonyos.com/', controller: this.controller })
    }
  }
}

代码运行效果图如下:

访问在线网页时您需要在module.json5文件中申明网络访问权限:ohos.permission.INTERNET。

{
    "module" : {
        "requestPermissions":[
           {
             "name": "ohos.permission.INTERNET"
           }
        ]
    }
}

加载本地网页

前面实现了Web组件加载在线网页,Web组件同样也可以加载本地网页。首先在main/resources/rawfile目录下创建一个HTML文件,然后通过$rawfile引用本地网页资源,示例代码如下:

// xxx.ets
@Entry
@Component
struct SecondPage {
  controller: WebController = new WebController();

  build() {
    Column() {
      Web({ src: $rawfile('index.html'), controller: this.controller })
    }
  }
}
// xxx.html



    


    

代码运行效果图如下:

为了方便开发者学习,后面用到的HTML都是以文件的形式放到rawfile目录下,加载本地网页。

3 网页缩放

有的网页可能不能很好适配手机屏幕,需要对其缩放才能有更好的效果,开发者可以根据需要给Web组件设置zoomAccess属性,zoomAccess用于设置是否支持手势进行缩放,默认允许执行缩放。Web组件默认支持手势进行缩放。

Web({ src:'www.example.com', controller:this.controller })
    .zoomAccess(true)

您还可以使用zoom(factor: number)方法用于设置网站的缩放比例。其中factor表示缩放倍数,下面示例,当点击一次按钮时,页面放大为原来的1.5倍。

// xxx.ets
@Entry
@Component
struct WebComponent {
  controller: WebController = new WebController();
  factor: number = 1.5;

  build() {
    Column() {
      Button('zoom')
        .onClick(() => {
          this.controller.zoom(this.factor);
        })
      Web({ src: 'www.example.com', controller: this.controller })
    }
  }
}

需要注意的是只有网页自身支持缩放,才能在Web组件里面进行缩放。

文本缩放

如果需要对文本进行缩放,可以使用textZoomAtio(textZoomAtio: number)方法。其中textZoomAtio用于设置页面的文本缩放百分比,默认值为100,表示100%,以下示例代码将文本放大为原来的1.5倍。

Web({ src:'www.example.com', controller:this.controller })
    .textZoomAtio(150)

效果图如下:

从上面的效果图可以看出使用textZoomAtio,文本会放大,但是图片不会随着文本一起放大。

4 Web组件事件

Web组件还提供了处理Javascript的对话框、网页加载进度及各种通知与请求事件的方法。例如onProgressChange可以监听网页的加载进度,onPageEnd在网页加载完成时触发该回调,且只在主frame触发,onConfirm则在网页触发confirm告警弹窗时触发回调。下面以onConfirm事件为例讲解Web组件事件的使用,更多Web组件事件可以查看事件。

Web组件处理JS confirm事件

如果您希望响应Web组件中网页的警告弹窗事件,您可以在onAlert或者onConfirm的回调方法中处理这些事件。以confirm弹窗为例,在网页触发onConfirm()告警弹窗时,显示一个AlertDialog弹窗。

// xxx.ets
@Entry
@Component
struct WebComponent {
  controller:WebController = new WebController();
  build() {
    Column() {
      Web({ src:$rawfile('index.html'), controller:this.controller })
        .onConfirm((event) => {
          AlertDialog.show({
            title: 'title',
            message: event.message,
            confirm: {
              value: 'onAlert',
              action: () => {
                event.result.handleConfirm();
              }
            },
            cancel: () => {
              event.result.handleCancel();
            }
          })
          return true;
        })
    }
  }
}

当onConfirm回调返回false时,触发默认弹窗。当回调返回true时,系统应用可以调用系统弹窗能力(包括确认和取消),并且需要根据用户的确认或取消操作调用JsResult通知Web组件。

在rawfile目录下创建如下HTML文件:

效果图如下:

5 Web和JavaScript交互

在开发专为适配Web组件的网页时,您可以实现Web组件和JavaScript代码之间的交互。Web组件可以调用JavaScript方法,JavaScript也可以调用Web组件里面的方法。

启用JavaScript

如果您希望加载的网页在Web组件中运行JavaScript,则必须为您的Web组件启用JavaScript功能,默认情况下是允许JavaScript执行的。

Web({ src:'https://www.example.com', controller:this.controller })
    .javaScriptAccess(true)

Web组件调用JS方法

您可以在Web组件onPageEnd事件中添加runJavaScript方法。事件是网页加载完成时的回调,runJavaScript方法可以执行HTML中的JavaScript脚本。

// xxx.ets
@Entry
@Component
struct WebComponent {
  controller: WebController = new WebController();
  @State webResult: string = ''
  build() {
    Column() {
      Text(this.webResult).fontSize(20)
      Web({ src: $rawfile('index.html'), controller: this.controller })
      .javaScriptAccess(true)
      .onPageEnd(e => {
        this.controller.runJavaScript({
          script: 'test()',
          callback: (result: string)=> {
            this.webResult = result;
          }});
      })
    }
  }
}

当页面加载完成时,触发onPageEnd事件,调用HTML文件中的test方法并将结果返回给Web组件。

JS调用Web组件方法

您可以使用registerJavaScriptProxy将Web组件中的JavaScript对象注入到window对象中,这样网页中的JS就可以直接调用该对象了。需要注意的是,要想registerJavaScriptProxy方法生效,须调用refresh方法。下面的示例将ets文件中的对象testObj注入到了window对象中。

// xxx.ets
@Entry
@Component
struct WebComponent{
  @State dataFromHtml: string = ''
  controller: WebController = new WebController()
  testObj = {
    test: (data) => {
      this.dataFromHtml = data;
      return 'ArkUI Web Component';
    },
    toString: () => {
      console.log('Web Component toString');
    }
  }

  build() {
    Column() {
      Text(this.dataFromHtml).fontSize(20)
      Row() {
        Button('Register JavaScript To Window').onClick(() => {
          this.controller.registerJavaScriptProxy({
            object: this.testObj,
            name: 'objName',
            methodList: ['test', 'toString'],
          });
          this.controller.refresh();
        })
      }

      Web({ src: $rawfile('index.html'), controller: this.controller })
        .javaScriptAccess(true)
    }
  }
}

其中object表示参与注册的对象,name表示注册对象的名称为objName,与window中调用的对象名一致;methodList表示参与注册的应用侧JavaScript对象的方法,包含test、toString两个方法。在HTML中使用的时候直接使用objName调用methodList里面对应的方法即可,示例如下:

// index.html




调用Web组件里面的方法


您还可以使用deleteJavaScriptRegister删除通过registerJavaScriptProxy注册到window上的指定name的应用侧JavaScript对象。

6 处理页面导航

当我们在使用浏览器浏览网页时,可以执行返回、前进、刷新等操作,Web组件同样支持这些操作。您可以使用backward()返回到上一个页面,使用forward()前进一个页面,您也可以使用refresh()刷新页面,使用clearHistory()来清除历史记录。下面通过一个简单的”浏览器”示例呈现这些功能。

// xxx.ets
@Entry
@Component
struct Page5 {
  controller: WebController = new WebController();

  build() {
    Column() {
      Row() {
        Button("前进").onClick(() => {
          this.controller.forward();
        })
        Button("后退").onClick(() => {
          this.controller.backward();
        })
        Button("刷新").onClick(() => {
          this.controller.refresh();
        })
        Button("停止").onClick(() => {
          this.controller.stop();
        })
        Button("清除历史").onClick(() => {
          this.controller.clearHistory();
        })
      }
      .padding(12)
      .backgroundColor(Color.Gray)
      .width('100%')

      Web({ src: 'https://developer.harmonyos.com/', controller: this.controller })
    }
    .height('100%')
  }
}

您可以使用accessBackward()来检查当前页面是否有后退来时记录,如果有则该方法返回 true。同样,您可以使用 accessForward()来检查是否存在前进历史记录。

7 调试网络应用

您可以使用onConsole获取网页输出的调试日志信息,当你在你的网页中使用console打印日志时,HarmonyOS系统都会调用相应的onConsole方法,这样你就可以获取到网页日志信息了。下面展示了如何在Web组件中使用onConsole输出网页中的日志:

// xxx.ets
@Entry
@Component
struct WebComponent {
  controller: WebController = new WebController();
  build() {
    Column() {
      Web({ src: $rawfile('index.html'), controller: this.controller })
         .onConsole((event) => {
          console.log('getMessage:' + event.message.getMessage());
          console.log('getMessageLevel:' + event.message.getMessageLevel());
          return false;
        })
    }
  }
}
// index.html



    




event的内容为ConsoleMessage,它包括一个对象来表示正在传递的日志信息的MessageLevel类型。您可以使用getMessageLevel()查询消息级别以确定消息的严重性,然后根据自身业务采取相应的操作。上面的示例代码,会打印如下所示的 日志消息:

08-27 19:47:27.476 27869-27937/com.example.webtest D 03B00/JSApp:  app Log: getMessage:info message
08-27 19:47:27.476 27869-27937/com.example.webtest D 03B00/JSApp:  app Log: getMessageLevel:3
08-27 19:47:27.478 27869-27937/com.example.webtest D 03B00/JSApp:  app Log: getMessage:error message
08-27 19:47:27.478 27869-27937/com.example.webtest D 03B00/JSApp:  app Log: getMessageLevel:1

8 参考链接

  1. Web组件的相关API参考:Web组件
  2. 应用权限参考:访问控制
    HTTP数据请求
     

    概述

    日常生活中我们使用应用程序看新闻、发送消息等,都需要连接到互联网,从服务端获取数据。例如,新闻应用可以从新闻服务器中获取最新的热点新闻,从而给用户打造更加丰富、更加实用的体验。

    那么要实现这样一种能实时从服务端获取数据的场景,就依赖于HTTP数据请求。

    2 什么是HTTP

    HTTP即超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。

    HTTP的工作原理正如上图所示,客户端向服务端发出一条HTTP数据请求,服务端接收请求后向客户端返回一些数据,然后客户端再对这些数据进行解析和处理。

    3 如何发起HTTP请求

    HTTP数据请求功能主要由http模块提供,包括发起请求、中断请求、订阅/取消订阅HTTP Response Header 事件等。

    在进行网络请求前,您需要在module.json5文件中申明网络访问权限。

    {
        "module" : {
            "requestPermissions":[
               {
                 "name": "ohos.permission.INTERNET"
               }
            ]
        }
    }

    应用访问网络需要申请ohos.permission.INTERNET权限,因为HarmonyOS提供了一种访问控制机制即应用权限,用来保证这些数据或功能不会被不当或恶意使用。关于应用权限的的详细信息开发者可以参考:访问控制

    您可以按照以下步骤完成HTTP数据请求:

    1. 导入http模块。
      import http from '@ohos.net.http';
    2. 创建httpRequest对象。

      使用createHttp()创建一个httpRequest对象,里面包括常用的一些网络请求方法,比如request、destroy、on('headerReceive')等。

      let httpRequest = http.createHttp();

      需要注意的是每一个httpRequest对象对应一个http请求任务,不可复用。

    3. 订阅请求头(可选)。

      用于订阅http响应头,此接口会比request请求先返回,可以根据业务需要订阅此消息。

      httpRequest.on('headersReceive', (header) => {
          console.info('header: ' + JSON.stringify(header));
      });
    4. 发起http请求。

      http模块支持常用的POST和GET等方法,封装在RequestMethod中。调用request方法发起网络请求,需要传入两个参数。第一个是请求的url地址,第二个是可选参数,类型为HttpRequestOptions,用于定义可选参数的类型和取值范围,包含请求方式、连接超时时间、请求头字段等。

      使用Get请求,参数内容需要拼接到URL中进行发送,如下示例中在url后面拼接了两个自定义参数,分别命名为param1和param2,值分别为value1和value2:

      let url= "https://EXAMPLE_URL?param1=v1&param2=v2";
      let promise = httpRequest.request(
        // 请求url地址
        url,
        {
          // 请求方式
          method: http.RequestMethod.GET,
          // 可选,默认为60s
          connectTimeout: 60000,
          // 可选,默认为60s
          readTimeout: 60000,
          // 开发者根据自身业务需要添加header字段
          header: {
            'Content-Type': 'application/json'
          }
        });
      POST请求参数需要添加到extraData里面,如下示例中在extraData里面定义添加了两个自定义参数param1和param2,值分别为value1和value2:
      let url = "https://EXAMPLE_URL";
      let promise = httpRequest.request(
        // 请求url地址
        url,
        {
          // 请求方式
          method: http.RequestMethod.POST,
          // 请求的额外数据。
          extraData: {
            "param1": "value1",
            "param2": "value2",
          },
          // 可选,默认为60s
          connectTimeout: 60000,
          // 可选,默认为60s
          readTimeout: 60000,
          // 开发者根据自身业务需要添加header字段
          header: {
            'Content-Type': 'application/json'
          }
        });
    5. 处理响应结果。

      data为网络请求返回的结果,err为请求异常时返回的结果。data的类型为HttpResponse

      promise.then((data) => { 
        if (data.responseCode === http.ResponseCode.OK) {
          console.info('Result:' + data.result);
          console.info('code:' + data.responseCode);
        }
      }).catch((err) => {
        console.info('error:' + JSON.stringify(err));
      });

      其中data.responseCode为http请求返回的状态码,如果状态码为http.ResponseCode.OK(即200),则表示请求成功,更多状态码可以在ResponseCode中查看。

      data.result为服务器返回的业务数据,开发者可以根据自身业务场景解析此数据。

    4 参考链接

    1. http数据请求参考:数据请求
    2. 应用权限参考:访问控制

     

    抽奖

    介绍

    本篇Codelab是基于ArkTS的声明式开发范式的样例,主要介绍了Web组件如何加载本地和云端H5小程序。所加载的页面是由HTML+CSS+JavaScript实现的完整小应用。样例主要包含以下功能:

    1. Web组件加载H5页面。
    2. ArkTS和H5页面交互。

    相关概念

    • Web:提供具有网页显示能力的Web组件。
    • runJavaScript:异步执行JavaScript脚本,并通过回调方式返回脚本执行的结果。
    • onConfirm:网页调用confirm()告警时触发此回调。本篇Codelab用于回显抽奖结果。

    相关权限

    本篇Codelab使用了在线网页,需要在配置文件module.json5里添加网络权限:ohos.permission.INTERNET。

    约束与限制

    本篇Codelab需要搭建服务端环境,服务端如何搭建将在代码工程目录的README中详细介绍,文档中不再赘述。

    完整示例

    gitee源码地址

     
    环境搭建

    我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。

    软件要求

    硬件要求

    • 设备类型:华为手机或运行在DevEco Studio上的华为手机设备模拟器。
    • HarmonyOS系统:3.1.0 Developer Release。

    环境搭建

    1. 安装DevEco Studio,详情请参考下载和安装软件
    2. 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
      • 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
      • 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境
    3. 开发者可以参考以下链接,完成设备调试的相关配置:
     
    代码结构解读

    本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。

     
     
    No Preview
    1. ├──entry/src/main/ets // 代码区
    2. │ ├──common
    3. │ │ └──Constant.ets // 常量类
    4. │ ├──entryability
    5. │ │ └──EntryAbility.ts // 程序入口类
    6. │ ├──pages
    7. │ │ ├──MainPage.ets // 主页入口文件
    8. │ │ └──WebPage.ets // 抽奖页入口文件
    9. │ └──viewmodel
    10. │ └──NavigatorModel.ets // 导航model
    11. ├──entry/src/main/resources
    12. │ ├──base
    13. │ │ ├──element // 尺寸、颜色、文字等资源文件存放位置
    14. │ │ ├──media // 媒体资源存放位置
    15. │ │ └──profile // 页面配置文件存放位置
    16. │ ├──en_US // 国际化英文
    17. │ ├──rawfile // 本地html代码存放位置
    18. │ └──zh_CN // 国际化中文
    19. └──HttpServerOfWeb // 服务端代码
    H5小程序

    抽奖小程序由HTML+CSS+JS实现,HTML代码使用无序列表实现抽奖盘布局。

    CSS代码设置抽奖盘的样式。

    JS代码实现抽奖的业务逻辑,并返回抽奖结果。

     
     
    No Preview
    1. // js/index.js
    2. function roll() {
    3. ...
    4. // 满足转圈数和指定位置就停止
    5. if (count >= totalCount && (prizesPosition + 1) === index) {
    6. clearTimeout(timer);
    7. isClick = true;
    8. speed = initSpeed;
    9. // 等待1s打开弹窗
    10. timer = setTimeout(openDialog, 1000);
    11. }
    12. ...
    13. }
    14. function startDraw() {
    15. ...
    16. if (isClick) {
    17. ...
    18. roll();
    19. isClick = false;
    20. }
    21. }
    22. function openDialog() {
    23. // confirm返回抽奖结果
    24. confirm(prizesArr[prizesPosition]);
    25. }
    Web组件

    启动应用进入首页,页面提供两个按钮,分别对应加载本地H5和加载云端H5,点击按钮跳转到抽奖页面。

    本地H5页面存放在resources/rawfile目录下,通过$rawfile()访问;云端H5页面则存放在HttpServerOfWeb服务器上,开发者可以根据代码工程目录README中服务端搭建流程进行服务器搭建。

    抽奖页面主要是由“点击抽奖”按钮和Web组件构成。给“点击抽奖”按钮绑定点击事件,实现点击按钮调用H5页面的JavaScript函数,并且通过onConfirm回调返回抽奖结果。在原生页面弹窗显示,完成ArkTS和H5的双向交互。

     
     
    Preview
    1. // WebPage.ets
    2. Column() {
    3. ...
    4. Web({ src: this.params['path'], controller: this.webController })
    5. ...
    6. // 网页调用confirm()告警时触发此回调
    7. .onConfirm((event) => {
    8. // 弹窗显示抽奖结果
    9. AlertDialog.show({
    10. message: WebConstant.WEB_ALERT_DIALOG_TEXT_VALUE + event?.message,
    11. ...
    12. })
    13. return true;
    14. })
    15. ...
    16. Column() {
    17. Text($r('app.string.textValue'))
    18. ...
    19. Text(this.params['tips'])
    20. ...
    21. }
    22. Button($r('app.string.btnValue'))
    23. ...
    24. .onClick(() => {
    25. // 异步执行JavaScript脚本
    26. this.webController.runJavaScript('startDraw()');
    27. })
    28. }
    总结

    您已经完成了本次Codelab的学习,并了解到以下知识点:

    1. 使用Web组件加载H5页面。

    2. 使用ArkTS与H5页面进行交互。

    3.  

     

    案例:新闻数据加载
    介绍

    本篇Codelab是基于ArkTS的声明式开发范式实现的样例,主要介绍了数据请求和touch事件的使用。包含以下功能:

    1. 数据请求。
    2. 列表下拉刷新。
    3. 列表上拉加载。

    相关概念

    • List组件:列表包含一系列相同宽度的列表项。
    • Tabs:通过页签进行内容视图切换。
    • TabContent:仅在Tabs中使用,对应一个切换页签的内容视图。
    • 数据请求:提供HTTP数据请求能力。
    • 触摸事件onTouch:触摸动作触发调用该方法。

    相关权限

    网络数据请求需要申请权限:ohos.permission.INTERNET。

    约束与限制

    本篇Codelab需要搭建服务端环境,服务端如何搭建将在代码工程目录的README中详细介绍,文档中不再赘述。

    完整示例

    gitee源码地址

     
    环境搭建

    我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。

    软件要求

    硬件要求

    • 设备类型:华为手机或运行在DevEco Studio上的华为手机设备模拟器。
    • HarmonyOS系统:3.1.0 Developer Release。

    环境搭建

    1. 安装DevEco Studio,详情请参考下载和安装软件
    2. 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
      • 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
      • 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境
    3. 开发者可以参考以下链接,完成设备调试的相关配置:
     
    代码结构解读
    本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。
     
     
    No Preview
    1. ├──entry/src/main/ets // ArkTS代码区
    2. │ ├──common
    3. │ │ ├──constant
    4. │ │ │ └──CommonConstant.ets // 公共常量类
    5. │ │ └──utils
    6. │ │ ├──HttpUtil.ets // 网络请求方法
    7. │ │ ├──Logger.ets // 日志工具类
    8. │ │ ├──PullDownRefresh.ets // 下拉刷新方法
    9. │ │ └──PullUpLoadMore.ets // 上拉加载更多方法
    10. │ ├──entryability
    11. │ │ └──EntryAbility.ts // 程序入口类
    12. │ ├──pages
    13. │ │ └──Index.ets // 主页面
    14. │ ├──view
    15. │ │ ├──CustomRefreshLoadLayout.ets // 下拉刷新、上拉加载布局文件
    16. │ │ ├──LoadMoreLayout.ets // 上拉加载布局封装
    17. │ │ ├──NewsItem.ets // 新闻数据
    18. │ │ ├──NewsList.ets // 新闻列表
    19. │ │ ├──NoMoreLayout.ets // 上拉停止布局封装
    20. │ │ ├──RefreshLayout.ets // 下拉刷新布局封装
    21. │ │ └──TabBar.ets // 新闻类型页签
    22. │ └──viewmodel
    23. │ ├──NewsModel.ets // 新闻模型类
    24. │ └──NewsViewModel.ets // 新闻ViewModel
    25. ├──entry/src/main/resources // 资源文件目录
    26. └──HttpServerOfNews // 服务端代码
    构建主界面

    本章节将介绍新闻列表页面的实现,用tabBar展示新闻分类,tabContent展示新闻列表,效果图如图所示:

    在TabBar.ets文件中的aboutToAppear()方法里获取新闻分类。

    在NewsList.ets文件中的aboutToAppear()方法里获取新闻数据,将数据加载到新闻列表页面ListLayout布局中。

     
     
    No Preview
    1. // NewsList.ets
    2. changeCategory() {
    3. this.newsModel.currentPage = 1;
    4. NewsViewModel.getNewsList(this.newsModel.currentPage, this.newsModel.pageSize, Const.GET_NEWS_LIST)
    5. .then((data: NewsData[]) => {
    6. this.newsModel.pageState = PageState.Success;
    7. if (data.length === this.newsModel.pageSize) {
    8. this.newsModel.currentPage++;
    9. this.newsModel.hasMore = true;
    10. } else {
    11. this.newsModel.hasMore = false;
    12. }
    13. this.newsModel.newsData = data;
    14. })
    15. .catch((err: string | Resource) => {
    16. promptAction.showToast({
    17. message: err,
    18. duration: Const.ANIMATION_DURATION
    19. });
    20. this.newsModel.pageState = PageState.Fail;
    21. });
    22. }
    23. aboutToAppear() {
    24. // 请求服务端新闻数据
    25. this.changeCategory();
    26. }
    27. ...
    28. @Builder ListLayout() {
    29. List() {
    30. ...
    31. ForEach(this.newsModel.newsData, (item: NewsData) => {
    32. ListItem() {
    33. // 新闻数据
    34. NewsItem({ newsData: item })
    35. }
    36. .height($r('app.float.news_list_height'))
    37. .backgroundColor($r('app.color.white'))
    38. .margin({ top: $r('app.float.news_list_margin_top') })
    39. .borderRadius(Const.NewsListConstant_ITEM_BORDER_RADIUS)
    40. }, (item: NewsData, index?: number) => JSON.stringify(item) + index)
    41. ...
    42. }
    43. ...
    44. }
    数据请求

    在module.json5文件中配置如右侧所示权限:

    这一章节,将基于新闻数据请求来介绍如何从服务端请求数据。

    导入http模块,封装httpRequestGet方法,调用者传入url地址发起网络数据请求。

    在NewsViewModel.ets文件中封装getNewsList方法,调用httpRequestGet方法请求服务端,用Promise异步保存返回的新闻数据列表。

     
     
    No Preview
    1. // NewsViewModel.ets
    2. // 获取服务端新闻数据列表
    3. getNewsList(currentPage: number, pageSize: number, path: string): Promise<NewsData[]> {
    4. return new Promise(async (resolve: Function, reject: Function) => {
    5. let url = `${Const.SERVER}/${path}`;
    6. url += '?currentPage=' + currentPage + '&pageSize=' + pageSize;
    7. httpRequestGet(url).then((data: ResponseResult) => {
    8. if (data.code === Const.SERVER_CODE_SUCCESS) {
    9. resolve(data.data);
    10. } else {
    11. Logger.error('getNewsList failed', JSON.stringify(data));
    12. reject($r('app.string.page_none_msg'));
    13. }
    14. }).catch((err: Error) => {
    15. Logger.error('getNewsList failed', JSON.stringify(err));
    16. reject($r('app.string.http_error_message'));
    17. });
    18. });
    19. }
    下拉刷新

    本章节将以下拉刷新的功能效果来介绍touch事件的使用。效果图如图所示:

    创建一个下拉刷新布局CustomLayout,动态传入刷新图片和刷新文字描述。

    将下拉刷新的布局添加到NewsList.ets文件中新闻列表布局ListLayout里面,监听ListLayout组件的onTouch事件实现下拉刷新。

    1. 在onTouch事件中,listTouchEvent方法判断触摸事件是否满足下拉条件。如右侧listTouchEvent所示:
    2. 在touchMovePullRefresh方法中,我们将对下拉的偏移量与下拉刷新布局的高度进行对比,如果大于布局高度并且在新闻列表的顶部,则表示达到刷新条件。如右侧touchMovePullRefresh所示:
    3. 在pullRefreshState方法中我们会对下拉刷新布局中的状态图片和描述进行改变,如右侧pullRefreshState所示。
    4. 当手指松开,才执行刷新操作。

    上拉加载也是通过touch事件来实现的,此处不再赘叙,有兴趣的同学可参考代码。

     
     
    No Preview
    1. // PullDownRefresh.ets
    2. export function listTouchEvent(newsModel: NewsModel, event: TouchEvent) {
    3. switch (event.type) {
    4. ...
    5. case TouchType.Move:
    6. if ((newsModel.isRefreshing === true) || (newsModel.isLoading === true)) {
    7. return;
    8. }
    9. let isDownPull = event.touches[0].y - newsModel.lastMoveY > 0;
    10. if (((isDownPull === true) || (newsModel.isPullRefreshOperation === true)) && (newsModel.isCanLoadMore === false))
    11. {
    12. // 手指移动,处理下拉刷新
    13. touchMovePullRefresh(newsModel, event);
    14. }
    15. ...
    16. break;
    17. }
    18. }
    19. export function touchMovePullRefresh(newsModel: NewsModel, event: TouchEvent) {
    20. if (newsModel.startIndex === 0) {
    21. newsModel.isPullRefreshOperation = true;
    22. let height = vp2px(newsModel.pullDownRefreshHeight);
    23. newsModel.offsetY = event.touches[0].y - newsModel.downY;
    24. // 滑动偏移量大于下拉刷新布局高度,满足刷新条件。
    25. if (newsModel.offsetY >= height) {
    26. pullRefreshState(newsModel, RefreshState.Release);
    27. newsModel.offsetY = height + newsModel.offsetY * Const.Y_OFF_SET_COEFFICIENT;
    28. } else {
    29. pullRefreshState(newsModel, RefreshState.DropDown);
    30. }
    31. if (newsModel.offsetY < 0) {
    32. newsModel.offsetY = 0;
    33. newsModel.isPullRefreshOperation = false;
    34. }
    35. }
    36. }
    37. export function pullRefreshState(newsModel: NewsModel, state: number) {
    38. switch (state) {
    39. ...
    40. case RefreshState.Release:
    41. newsModel.pullDownRefreshText = $r('app.string.release_refresh_text');
    42. newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_refresh');
    43. newsModel.isCanRefresh = true;
    44. newsModel.isRefreshing = false;
    45. break;
    46. case RefreshState.Refreshing:
    47. newsModel.offsetY = vp2px(newsModel.pullDownRefreshHeight);
    48. newsModel.pullDownRefreshText = $r('app.string.refreshing_text');
    49. newsModel.pullDownRefreshImage = $r('app.media.ic_pull_up_load');
    50. newsModel.isCanRefresh = true;
    51. newsModel.isRefreshing = true;
    52. break;
    53. case RefreshState.Success:
    54. newsModel.pullDownRefreshText = $r('app.string.refresh_success_text');
    55. newsModel.pullDownRefreshImage = $r('app.media.ic_succeed_refresh');
    56. newsModel.isCanRefresh = true;
    57. newsModel.isRefreshing = true;
    58. break;
    59. ...
    60. default:
    61. break;
    62. }
    63. }
    总结

    您已经完成了本次Codelab的学习,并了解到以下知识点:

    1. 使用List组件实现数据列表。

    2. 使用Tabs、TabContent组件实现内容视图切换。

    3. 网络数据请求。

    4. 触摸事件onTouch的使用。

     

     

     原生页面调用 web 方法

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

posted @ 2024-01-21 21:57  freedragon  阅读(47)  评论(0编辑  收藏  举报