当前位置:   article > 正文

HarmonyOS开发(八):动画及网络_arkts image rotate

arkts image rotate

1、动画概述

在ArkUI中,产生动画的方式是改变组件属性值并且指定相关的动画参数。当属性值发生变化后,按照动画参数,从原来的状态过渡到新的状态,就形成一个动画。

动画的相关参数如下:

属性名称

属性类型

默认值

描述

duration

number

1000

动画时长,单位为毫秒,默认时长为1000毫秒。

temponumber1.0动画播放的速度,值越大则播放越快,值越小则播放越慢,0则表示没有动画效果
curveCurveCurve.Linear

动画变化曲线,默认曲线为线性

其中可取值有如下一些

Liner:表示从头到尾的速度都是相同的

Ease:表示以低速开始,然后加快,在结束前变慢CubicBezier(0.25,0.1,0.25,1.0)

EaseIn:表示以低速开始 CubicBezier(0.42,0.0,1.0,1.0)

EaseOut:表示以低速结束 CubicBezier(0.0,0.0,0.58,1.0)

EaseInOut:表示以低速开始和结束 CubicBezier(0.42,0.0,0.58,1.0)

FastOutSlowIn:标准曲线 CubicBezier(0.4,0.0,0.2,1.0)

LinearOutSlowIn:减速曲线 CubicBezier(0.0,0.0,0.2,1.0)

FastOutSlowIn:加速曲线 CubicBezier(0.4,0.0,1.0,1.0)

ExtremeDeceleratioin:急缓曲线 CubicBezier(0.0,0.0,0.0,1.0)

sharp:锐利曲线 CubicBezier(0.33,0.0,0.67,1.0)

Rhythm:节奏曲线 CubicBezier(0.7,0.0,0.2,1.0)

Smooth:平滑曲线 CubicBezier(0.4,0.0,0.4,1.0)

Friction:阻尼曲线 CubicBezier(0.2,0.0,0.2,1.0)

delaynumber0延时播放时间,单位为毫秒,默认不延时播放
iterationsnumber1播放次数,默认为1次,设置为-1则表示无限次播放
playModePlayModePlayMode.Normal

设置动画播放模式,默认播放完后重头播放

Normal:正常播放

Reverse:动画反向播放

Alternate:动画在奇数次正向播放,偶数次反向播放

AlternateReverse:动画在奇数次反向播放,偶数次正向播放

onFinishfunction动画播放结束时回调函数

2、动画分类

  • 从页面分类分为:页面内的动画(在一个页面中即可发生的动画)、页面间的动画(两个页面跳转时会产生的动画)
  • 按基础能力可分为:属性动画、显示动画、转场动画

3、页面内动画

3.1、布局更新动画

显示动画(animateTo)和属性动画(animation)是ArkUI提供的最基础和常用的动画功能。

在布局属性(如:尺寸、位置等属性)发生变化时,可以通过属性动画或显示动画,按动画参数过渡到新的布局参数状态。

动画类型特点
显示动画(函数)闭包内的变化均会触发动画,包含币数据变化引起的组件增删
属性动画(属性方法)属性变化自动触发动画。(注意:属性值的变化需要加在animation属性之前)

3.1.1、使用显示动画产生布局更新动画

显示动画的接口:

animateTo(value:AnimateParam, event: () => void): void

第一个参数:指定动画参数

第二个参数:动画的闭包函数

3.1.2、相关实例

  1. @Entry
  2. @Component
  3. struct LayoutChangeTest {
  4. @State itemAlign: HorizontalAlign = HorizontalAlign.Start;
  5. aligns: HorizontalAlign[] = [HorizontalAlign.Start, HorizontalAlign.Center, HorizontalAlign.End];
  6. alignIndex: number = 0;
  7. build() {
  8. Column({space: 30}) {
  9. Text('修改布局位置')
  10. .fontSize(30)
  11. .margin({top: 100})
  12. Column({space: 25}) {
  13. Text("JavaScript").fontSize(20).fontWeight(FontWeight.Bolder).fontColor('#4e72b8')
  14. Text("TypeScript").fontSize(20).fontWeight(FontWeight.Bolder).fontColor('#6d8346')
  15. Text("ArkTS").fontSize(20).fontWeight(FontWeight.Bolder).fontColor('#69541b')
  16. }
  17. .margin(20)
  18. .alignItems(this.itemAlign)
  19. .justifyContent(FlexAlign.Center)
  20. .borderWidth(2)
  21. .width('90%')
  22. .height(200)
  23. Button('Click', {type: ButtonType.Capsule, stateEffect: true})
  24. .fontSize(18)
  25. .fontWeight(FontWeight.Bold)
  26. .width('50%')
  27. .onClick(() => {
  28. // 显示动画
  29. animateTo({duration: 1000, curve: Curve.EaseInOut},() => {
  30. // 在闭包函数中修改上方元素的对齐方式
  31. this.alignIndex = (this.alignIndex + 1) % this.aligns.length;
  32. this.itemAlign = this.aligns[this.alignIndex];
  33. })
  34. })
  35. }
  36. .width('100%')
  37. .height('100%')
  38. }
  39. }
  1. @Entry
  2. @Component
  3. struct LayoutChangeTest1 {
  4. @State mySize: number = 30;
  5. // 标志位,用来控制组件的大小
  6. @State flag: boolean = false;
  7. build() {
  8. Column( {space: 20} ) {
  9. Text('HarmonyOS')
  10. .fontColor('#ed1941')
  11. .fontWeight(FontWeight.Bolder)
  12. .fontSize(this.mySize)
  13. .margin(10)
  14. Button(this.flag ? '缩小': '放大', {type:ButtonType.Capsule,stateEffect:true})
  15. .width('50%')
  16. .fontSize(16)
  17. .onClick(() => {
  18. animateTo({duration: 1000, curve: Curve.Ease}, () => {
  19. if(this.flag) {
  20. this.mySize = 30;
  21. } else {
  22. this.mySize = 50;
  23. }
  24. this.flag = !this.flag;
  25. });
  26. })
  27. }
  28. .justifyContent(FlexAlign.Center)
  29. .width('100%')
  30. .height('100%')
  31. }
  32. }
  1. @Entry
  2. @Component
  3. struct LayoutPage2 {
  4. @State message: string = '改变角度';
  5. @State rotateAngle: number = 0;
  6. @State flag: boolean = false;
  7. build() {
  8. Row() {
  9. Column({space:15}) {
  10. Text(this.message)
  11. .fontSize(50)
  12. .fontWeight(FontWeight.Bold)
  13. Image($r('app.media.image2'))
  14. .width(200)
  15. .height(200)
  16. .borderRadius(100)
  17. .rotate({
  18. x: 1,
  19. y: 1,
  20. z: 1,
  21. angle: this.rotateAngle
  22. })
  23. .onClick(() => {
  24. animateTo({},() => {
  25. if(this.flag) {
  26. this.rotateAngle = 0;
  27. } else {
  28. this.rotateAngle = 640;
  29. }
  30. this.flag = !this.flag;
  31. })
  32. })
  33. }
  34. .width('100%')
  35. }
  36. .height('100%')
  37. }
  38. }

3.1.3、使用属性动画产生布局更新动画

显示动画是把要执行动画的属性修改放在闭包函烽中触发动画,而属性动画则不需要使用闭包,只需要把animation属性加在要做属性动画的组件的属性后就可以了。

属性动画接口

animation(value: AnimateParam)

参数value表示动画参数。

注意:如果希望某个属性值的变化而产生动画,则需要此属性需要加到animation属性之前。

3.1.4、相关案例

  1. @Entry
  2. @Component
  3. struct AttrAnimationTest1 {
  4. @State widthSize: number = 250;
  5. @State heightSize: number = 100;
  6. @State rotateAngle: number = 0;
  7. @State flag: boolean = true;
  8. build() {
  9. Row() {
  10. Column() {
  11. Button('change size')
  12. .onClick(() => {
  13. if(this.flag) {
  14. this.widthSize = 150;
  15. this.heightSize = 50;
  16. } else {
  17. this.widthSize = 250;
  18. this.heightSize = 100;
  19. }
  20. this.flag = !this.flag;
  21. })
  22. .margin(30)
  23. .width(this.widthSize)
  24. .animation({
  25. duration:2000,
  26. iterations:3,
  27. curve: Curve.Linear,
  28. playMode: PlayMode.Alternate
  29. })
  30. .height(this.heightSize)
  31. .animation({
  32. duration:1000,
  33. curve: Curve.Linear,
  34. playMode:PlayMode.Alternate
  35. })
  36. Button('change rotate angle')
  37. .onClick(() => {
  38. this.rotateAngle = 90;
  39. })
  40. .margin(50)
  41. .rotate({angle: this.rotateAngle})
  42. .animation({
  43. duration:1000,
  44. iterations:-1,
  45. curve:Curve.Linear,
  46. playMode:PlayMode.Alternate
  47. })
  48. }
  49. .width('100%')
  50. }
  51. .height('100%')
  52. }
  53. }

4、组件内转场动画

组件内转场动画使用transition,它常见的用法如下:

1、if/else产生组件内转场动画

2、ForEach产生组件内转场动画

组件的插入、删除过程即为组件本身的转场过程,通过设置转场动画,可以定义组件出现、消失的效果。

组件内转场动画的接口:

transition(value: TransitionOptions)

transition函数的入参为组件内转场的效果,可以定义平移、透明度、旋转、缩放这几种转场样式的单个或者组件的转场效果,必须和animateTo一起使用才能产生组件转场效果。

transition常见用法

1、组件的插入、删除使用同一个动画效果

  1. Button()
  2. .transition({type: TransitionType.All, scale: {x: 0, y: 0 }})

当type属性为TransitionType.All时,表示指定转场动效生效在组件的所有变化(插入和删除)场景,这个时候删除动画和插入动画是相反的过程。

 2、组件的插入、删除使用不同的动画效果

  1. Button()
  2. .transition({type: TransitionType.Insert, translate: {x: 200, y: -200}, opacity: 0})
  3. .transition({type: TransitionType.Delete, rotate: {x: 0, y:0, z:1, angle:360}})

3、只定义组件的插入或删除其中一种动画效果

  1. Button()
  2. .transition({type: TransitionType.Delete, translate:{x: 200,y: -200}})

4.1、if/else产生组件内转场动画

  1. @Entry
  2. @Component
  3. struct TransitionTest {
  4. @State flag: boolean = true;
  5. build() {
  6. Row() {
  7. Column() {
  8. Button(this.flag ? '隐藏' : '显示')
  9. .fontSize(20)
  10. .margin(30)
  11. .width(150)
  12. .height(50)
  13. .onClick(() => {
  14. // 在animateTo闭包中改变flag的值
  15. animateTo({duration:1500},() => {
  16. // 点击按钮来控制标记变量
  17. this.flag = !this.flag;
  18. })
  19. })
  20. if(this.flag) {
  21. Text('HarmonyOS')
  22. .fontSize(20)
  23. .fontWeight(FontWeight.Bolder)
  24. .fontColor('#008792')
  25. // 添加转场效果
  26. .transition({type: TransitionType.Insert, translate: {x: 200, y: -200}})
  27. .transition({type: TransitionType.Delete, opacity: 0, scale: {x: 0, y: 0}})
  28. }
  29. }
  30. .width('100%')
  31. }
  32. .height('100%')
  33. }
  34. }

4.2、ForEach产生组件内转场动画

ForEach可通过控制数组中的元素个数,来控制组件的插入和删除。通过ForEach来产生组件内转场动画,需要两个条件

1、ForEach里的组件配置了transition效果

2、在animateTo的闭包中控制组件的插入或删除,即控制数组的元素添加和删除

  1. @Entry
  2. @Component
  3. struct ForEachTest {
  4. @State books :string[] = [
  5. '《JavaScript学习指南》',
  6. '《TypeScript从入门到精通》',
  7. '《ArkTS学习手册》',
  8. '《JAVA核心卷》'
  9. ];
  10. num: number = 0;
  11. build() {
  12. Column({space: 10}) {
  13. Column(){
  14. // 注意 这里遍历的key是使用item,所以我们在添加时加上一个num来区分内容
  15. ForEach(this.books, (item) => {
  16. Text(item).textStyle()
  17. .transition({type: TransitionType.All, translate: {x: 200},scale:{x:0,y:0}})
  18. },item => JSON.stringify(item))
  19. }.columnStyle()
  20. Button('头部添加元素').ButtonStyle('#375830', () => {
  21. animateTo({}, () => {
  22. this.num++;
  23. this.books.unshift(`《C语言编程思想》_${this.num}`)
  24. })
  25. })
  26. Button('头部删除元素').ButtonStyle('#b64533', () => {
  27. animateTo({}, () => {
  28. this.books.shift()
  29. })
  30. })
  31. Button('尾部删除元素').ButtonStyle('#dea32c', () => {
  32. animateTo({}, () => {
  33. this.books.pop()
  34. })
  35. })
  36. }
  37. .width('100%')
  38. .height('100%')
  39. }
  40. }
  41. // 相关样式信息
  42. @Extend(Text) function textStyle() {
  43. .width(300)
  44. .height(60)
  45. .fontSize(18)
  46. .margin({top: 3})
  47. .backgroundColor('#d3c6a6')
  48. .textAlign(TextAlign.Start)
  49. .fontColor(Color.White)
  50. }
  51. @Extend(Column) function columnStyle() {
  52. .margin(10)
  53. .justifyContent(FlexAlign.Start)
  54. .alignItems(HorizontalAlign.Center)
  55. .width('90%')
  56. .height('50%')
  57. }
  58. @Extend(Button) function ButtonStyle(color: string|Color, click: Function) {
  59. .width(200)
  60. .height(50)
  61. .fontSize(18)
  62. .backgroundColor(color)
  63. .onClick(() => {
  64. // click代表的就是调用时具体传入进来的函数
  65. click()
  66. })
  67. }

5、页面间的动画

5.1、共享元素转场动画

在不同的页面间,有使用相同元素的场景,可以使用共享元素转场动画衔接。

共享元素转场的接口:

sharedTransition(id: string, options?: sharedTransitionOptions)

其中id为指定共享元素的组件id

根据sharedTransitionOptions中的type参数,可以把共享元素转场分为Exchange类型和Static类型。

5.1.1、Exchange类型

交换型共享元素转场。

这种类共享元素转场适用于两个页面间相同元素的衔接,从起始页共享元素的位置、大小过渡到目标页面的共享元素的位置、大小。

当不指定type时,默认就是Exchange类型的共享转场

使用Exchange类型的共享转场时,共享元素转场的动画参数由目标页面options中的动画参数决定。

5.1.2、Static类型的共享元素转场

静态类型的共享元素转场常用于页面跳转时,标题的渐入淡出,只需要在一个页面中有Static的共享元素,不能在两个页面中出现相同id的Static类型的共享元素。

  1. // Src.ets
  2. import router from '@ohos.router';
  3. @Entry
  4. @Component
  5. struct Src {
  6. build() {
  7. Column({ space: 30 }) {
  8. // Exchange类型共享转场
  9. Image($r('app.media.image2'))
  10. .width(50)
  11. .height(50)
  12. .opacity(.3)
  13. .borderRadius(75)
  14. .sharedTransition('img1',{
  15. duration: 1000,
  16. curve: Curve.Linear
  17. })
  18. }
  19. .onClick(() => {
  20. // 路由跳转
  21. router.pushUrl({url: "pages/SharedTransition/Dest"});
  22. })
  23. .padding(10)
  24. .width('100%')
  25. .height('100%')
  26. .alignItems(HorizontalAlign.Start)
  27. }
  28. }
  1. // Dest.ets
  2. import router from '@ohos.router';
  3. @Entry
  4. @Component
  5. struct Dest {
  6. build() {
  7. Column({ space: 30 }) {
  8. // 配置Static类型的共享元素转场
  9. Text('鸿蒙系统')
  10. .fontSize(20)
  11. .fontColor('#6d8346')
  12. .opacity(.8)
  13. .fontWeight(FontWeight.Bold)
  14. .margin({ top: 10 })
  15. .sharedTransition('text',{
  16. duration: 500,
  17. curve: Curve.Linear,
  18. type: SharedTransitionEffectType.Static
  19. })
  20. // 配置Exchange类型的共享元素转场,id是'img1'
  21. Image($r('app.media.image2'))
  22. .width(150)
  23. .height(150).opacity(1)
  24. .borderRadius(75)
  25. .sharedTransition('img1',{
  26. duration: 500,
  27. curve: Curve.Linear
  28. })
  29. }
  30. .width('100%')
  31. .height('100%')
  32. .alignItems(HorizontalAlign.Center)
  33. .onClick(() => {
  34. // 返回
  35. router.back();
  36. })
  37. }
  38. }

5.2、页面转场动画

两个页面之间发生跳转,一个页面消失,另一个页面出现,此时可以配置各自页面的页面转场参数实现自定义的页面转场效果。

页面转场效果写在pageTransition函数中,通过PageTransitionEnter和PageTransitionExit来指定页面进入和退出时的动画效果。

pageTransitionEnter接口

PageTransitionEnter({type?: RouteType, duration?: number, curve?: Curve | string, delay: number})

pageTransitionEnter提供了onEnter接口进行自定义页面入场动画的回调

pageTransitionExit接口

PageTransitionExit({type?: RouteType, duration?: number, curve?: Curve | string, delay: number})

pageTransitionExit提供了onExit接口进行自定义页面退场动画的回调

关于RouteType表示路由生效类型,从一个页面到另一个页面有两人种方式,一种是push,一种是back(pop出栈),那么type参数就可以由开发者指定哪种类型的路由来定义转场效果。对于push和back会有一些区别,比如A页面到B页面push时,A页面是退场,B页面是入场,如果B页面back回A页面则是B页面退场,A页面入场。

type参数的默认值是RouteType.None表示对页面的push和pop都生效

如果我们把页面转场时长设置为0(duration参数值为0)则无页面转场动画。

  1. // Src2.est
  2. import router from '@ohos.router';
  3. @Entry
  4. @Component
  5. struct Src2 {
  6. @State scale1: number = 1;
  7. @State opacity1: number = 1;
  8. build() {
  9. Column({ space: 30}) {
  10. Text('Src2...')
  11. .fontSize(30)
  12. .opacity(this.opacity1)
  13. .margin({bottom: 15})
  14. Image($r('app.media.image2'))
  15. .width(300)
  16. .height(400)
  17. .scale({x: this.scale1})
  18. .opacity(this.opacity1)
  19. }
  20. .width('100%')
  21. .height('100%')
  22. .onClick(() => {
  23. router.pushUrl({
  24. url: "pages/pageTransition/Dest2"
  25. })
  26. })
  27. }
  28. pageTransition() {
  29. PageTransitionEnter({}).onEnter((type: RouteType, progress: number) => {
  30. this.scale1 = 1;
  31. this.opacity1 = progress;
  32. })
  33. PageTransitionExit({}).onExit((type: RouteType, progress: number) => {
  34. this.scale1 = 1 - progress;;
  35. this.opacity1 = 1 - progress;
  36. })
  37. }
  38. }
  1. // Dest2.est
  2. import router from '@ohos.router';
  3. @Entry
  4. @Component
  5. struct Dest2 {
  6. @State scale1: number = 1;
  7. @State opacity1: number = 1;
  8. build() {
  9. Column(){
  10. Text('Dest2...')
  11. .fontSize(30)
  12. .opacity(this.opacity1)
  13. .margin({bottom: 15})
  14. Image($r('app.media.image2'))
  15. .width(300)
  16. .height(400)
  17. .scale({y: this.scale1})
  18. .opacity(this.opacity1)
  19. }
  20. .width('100%')
  21. .height('100%')
  22. .onClick(() => {
  23. router.back()
  24. })
  25. }
  26. pageTransition() {
  27. PageTransitionEnter({}).onEnter((type: RouteType, progress: number) => {
  28. this.scale1 = progress;
  29. this.opacity1 = progress;
  30. })
  31. PageTransitionExit({}).onExit((type: RouteType, progress: number) => {
  32. this.scale1 = 1 - progress;
  33. this.opacity1 = 1 - progress;
  34. })
  35. }
  36. }

6、网络

6.1、基于web组件构建网络应用

当需要访问网络资源的时候需要在module.json5中申请网络访问权限:ohos.permission.INTERNET

Web组件的使用只需要ArkTS文件中创建一个Web组件,传入两个参数就可以了。

src:指定了网页的路径

controller:组件控制器,绑定web组件,实现对web组件的控制

  1. import webview from '@ohos.web.webview';
  2. @Entry
  3. @Component
  4. struct WebComp {
  5. controller: WebviewController = new webview.WebviewController();
  6. build() {
  7. Row() {
  8. Column() {
  9. Web({
  10. src: 'https://www.baidu.com',
  11. controller: this.controller
  12. })
  13. }
  14. .width('100%')
  15. }
  16. .height('100%')
  17. }
  18. }

6.1.1、本地网页加载

首先本的网页文件可以放在rawfile目录中

  1. <!-- index.html -->
  2. <!doctype html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport"
  7. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  8. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  9. <title>Document</title>
  10. </head>
  11. <body>
  12. <div>
  13. <h2>加载本地网页</h2>
  14. </div>
  15. <div>
  16. <img src="../base/media/img1.png" width="300" height="400">
  17. </div>
  18. </body>
  19. </html>

在ets文件中对这个页面进行加载展示

  1. import webview from '@ohos.web.webview'
  2. @Entry
  3. @Component
  4. struct WebComp2 {
  5. controller: WebviewController = new webview.WebviewController();
  6. build() {
  7. Row() {
  8. Column() {
  9. Web({
  10. src: $rawfile('index.html'),
  11. controller: this.controller
  12. })
  13. }
  14. .width('100%')
  15. }
  16. .height('100%')
  17. }
  18. }

6.1.2、网页缩放能力

有时网页可能不能与手机屏幕很好地适配,需要对其缩放才能有更好的效果,这个时候可以给Web组件zoomAccess属性,它用来设置是否支持手势 进行缩放,默认是行缩放的。

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

还可以使用zoom(factor: number)方法用于设置网站的缩放比例,参数factor表示缩放的倍数

  1. import webview from '@ohos.web.webview';
  2. @Entry
  3. @Component
  4. struct WebComp {
  5. controller: WebviewController = new webview.WebviewController();
  6. build() {
  7. Row() {
  8. Column() {
  9. Button('zoom+')
  10. .width('50%')
  11. .onClick(() => {
  12. this.controller.zoom(1.5)
  13. })
  14. Web({
  15. src: 'https://www.baidu.com',
  16. controller: this.controller
  17. })
  18. }
  19. .width('100%')
  20. }
  21. .height('100%')
  22. }
  23. }

上面示例每次点击zoom+时会把页面放大为原来的1.5倍。

6.1.3、文本缩放

如果需要对文本进行缩放,可以使用textZoomAtio(textZoomAtio: number)方法

textZoomRatio为缩放的百分比,默认值是100,表示100%

  1. import webview from '@ohos.web.webview';
  2. @Entry
  3. @Component
  4. struct WebComp {
  5. @State textZoom: number = 100;
  6. controller: WebviewController = new webview.WebviewController();
  7. build() {
  8. Row() {
  9. Column() {
  10. Button('文大文本+')
  11. .width('50%')
  12. .onClick(() => {
  13. this.textZoom += 20;
  14. })
  15. Web({
  16. src: 'https://www.baidu.com',
  17. controller: this.controller
  18. }).textZoomRatio(this.textZoom)
  19. }
  20. .width('100%')
  21. }
  22. .height('100%')
  23. }
  24. }

6.1.4、web组件事件

web组件还提供了处理JavaScript的对话框、网页加载进度及各种通知与请求事件的方法。

onProgressChange        监听网页的加载进度

onPageEnd                在网页加载完时触发此回调

onConfirm                在网页触发confirm告警弹窗时触发回调

  1. <!-- index.html -->
  2. <!doctype html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport"
  7. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  8. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  9. <title>Document</title>
  10. </head>
  11. <body>
  12. <div>
  13. <h2>加载本地网页</h2>
  14. </div>
  15. <div>
  16. <img src="../base/media/img1.png" width="300" height="400">
  17. </div>
  18. <script type="text/javascript">
  19. confirm('confirm message from html')
  20. </script>
  21. </body>
  22. </html>

  1. import webview from '@ohos.web.webview'
  2. @Entry
  3. @Component
  4. struct WebComp2 {
  5. controller: WebviewController = new webview.WebviewController();
  6. build() {
  7. Row() {
  8. Column() {
  9. Web({
  10. src: $rawfile('index.html'),
  11. controller: this.controller
  12. })
  13. .zoomAccess(true)
  14. .onConfirm((event) =>{
  15. AlertDialog.show({
  16. title: 'title',
  17. message: event.message,
  18. confirm: {
  19. value: 'onAlert',
  20. action: () => {
  21. event.result.handleConfirm();
  22. }
  23. },
  24. cancel: () => {
  25. event.result.handleCancel();
  26. }
  27. })
  28. return true;
  29. })
  30. }
  31. .width('100%')
  32. }
  33. .height('100%')
  34. }
  35. }

6.1.5、web与javascript的交互

 web组件可以调用JavaScript方法,JavaScript也可以调用Web组件里的方法

web组件启用javascript

如果在web组件中运行javascript,则必须要在web组件中启用javascript功能,默认情况下是不可以执行javascript的。

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

 web组件调用JS方法

比如在web组件onPageEnd事件中添加runJavaScript方法,这个事件是在网页加载完成时的回调,runJavaScript方法可以执行HTML中的JavaScript脚本

  1. <!-- index.html -->
  2. <!doctype html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport"
  7. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  8. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  9. <title>Document</title>
  10. </head>
  11. <body>
  12. <div>
  13. <h2>加载本地网页</h2>
  14. </div>
  15. <div>
  16. <img src="../base/media/img1.png" width="300" height="400">
  17. </div>
  18. <script type="text/javascript">
  19. function test() {
  20. return "this value is from index.html"
  21. }
  22. </script>
  23. </body>
  24. </html>
  1. import webview from '@ohos.web.webview'
  2. @Entry
  3. @Component
  4. struct WebComp2 {
  5. controller: WebviewController = new webview.WebviewController();
  6. @State webResult: string = ''
  7. build() {
  8. Row() {
  9. Column() {
  10. Text(this.webResult)
  11. .fontSize(16)
  12. Web({
  13. src: $rawfile('index.html'),
  14. controller: this.controller
  15. })
  16. .zoomAccess(true)
  17. .javaScriptAccess(true)
  18. .onPageEnd(e => {
  19. this.controller.runJavaScript('test()',(err,data)=>{
  20. if(!err) {
  21. this.webResult = data;
  22. }
  23. })
  24. // promise化的写法
  25. // let promise = this.controller.runJavaScript('test()');
  26. // promise.then((data) => {
  27. // this.webResult = data;
  28. // })
  29. })
  30. }
  31. .width('100%')
  32. }
  33. .height('100%')
  34. }
  35. }

 js调用web组件方法

开发者者使用Web组件把应用侧代码注册到前端页面中,注册完成之后,前端页面中使用注册的对象名称就可以调用应用侧的函数,从而实现前端页面中调用应用侧的方法。

注册应用侧代码有两种方式:

一种是Web组件初始化使用调用,使用javaScriptProxy()接口。

一种是在Web组件初始化完成后调用,使用registerJavaScriptProxy()接口

javaScriptProxy()接口使用示例:

  1. // xxx.ets
  2. import web_webview from '@ohos.web.webview';
  3. @Entry
  4. @Component
  5. struct WebComponent {
  6. webviewController: web_webview.WebviewController = new web_webview.WebviewController();
  7. // 声明需要注册的对象
  8. testObj = {
  9. test: () => {
  10. return 'ArkTS Hello World!';
  11. }
  12. }
  13. build() {
  14. Column() {
  15. // web组件加载本地index.html页面
  16. Web({ src: $rawfile('index.html'), controller: this.webviewController})
  17. // 将对象注入到web端
  18. .javaScriptProxy({
  19. object: this.testObj,
  20. name: "testObjName",
  21. methodList: ["test"],
  22. controller: this.webviewController
  23. })
  24. }
  25. }
  26. }

应用侧使用registerJavaScriptProxy()接口注册

  1. // xxx.ets
  2. import web_webview from '@ohos.web.webview';
  3. @Entry
  4. @Component
  5. struct Index {
  6. webviewController: web_webview.WebviewController = new web_webview.WebviewController();
  7. testObj = {
  8. test: (data) => {
  9. return "ArkUI Web Component";
  10. },
  11. toString: () => {
  12. console.info('Web Component toString');
  13. }
  14. }
  15. build() {
  16. Column() {
  17. Button('refresh')
  18. .onClick(() => {
  19. try {
  20. this.webviewController.refresh();
  21. } catch (error) {
  22. console.error(`Errorcode: ${error.code}, Message: ${error.message}`);
  23. }
  24. })
  25. Button('Register JavaScript To Window')
  26. .onClick(() => {
  27. try {
  28. this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
  29. } catch (error) {
  30. console.error(`Errorcode: ${error.code}, Message: ${error.message}`);
  31. }
  32. })
  33. Web({ src: $rawfile('index.html'), controller: this.webviewController })
  34. }
  35. }
  36. }

注意: 使用registerJavaScriptProxy()接口注册方法时,注册后需调用refresh()接口生效

  1. <!-- index.html -->
  2. <!DOCTYPE html>
  3. <html>
  4. <body>
  5. <button type="button" onclick="callArkTS()">Click Me!</button>
  6. <p id="demo"></p>
  7. <script>
  8. function callArkTS() {
  9. let str = objName.test();
  10. document.getElementById("demo").innerHTML = str;
  11. console.info('ArkTS Hello World! :' + str);
  12. }
  13. </script>
  14. </body>
  15. </html>

 6.1.6、页面导航处理

当使用浏览器浏览网页时,可以执行返回、前进、刷新等操作,Web组件也支持这些操作。可以使用backward()回到上一个页面,forward()前进一个页面,refresh()刷新页面,clearHistory()清除历史记录。

  1. import webview from '@ohos.web.webview'
  2. @Entry
  3. @Component
  4. struct NavigatorTest {
  5. controller: WebviewController = new webview.WebviewController();
  6. build() {
  7. Row() {
  8. Column() {
  9. Row() {
  10. Button('前进').onClick(() => {
  11. this.controller.forward();
  12. })
  13. Button('后退').onClick(() => {
  14. this.controller.backward();
  15. })
  16. Button('刷新').onClick(() => {
  17. this.controller.refresh();
  18. })
  19. Button('停止').onClick(() => {
  20. this.controller.stop();
  21. })
  22. Button('清理历史').onClick(() => {
  23. this.controller.stop();
  24. })
  25. }
  26. .padding(5)
  27. .backgroundColor(Color.Gray)
  28. .width('100%')
  29. .justifyContent(FlexAlign.SpaceAround)
  30. Web({src: 'https://www.baidu.com', controller: this.controller})
  31. }
  32. .width('100%')
  33. }
  34. .height('100%')
  35. }
  36. }


6.2、HTTP数据请求

6.2.1、简单说明

开发的应用需要通过HTTP发送一个数据请求,支持的情求方式有:GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT

HTTP数据请求功能主要由http模块提供,这个功能也需要申请ohos.permission.INTERNET权限

相关的方法说明:

方法名称功能描述
createHttp()创建一个http请求
request()根据URL地址,发起HTTP网络请求
destroy()中断请求任务
on(type: 'headerReceive')订阅HTTP Response Header 事件
off(type: 'headerReceive')取消订阅HTTP Response Header事件

6.2.2、开发步骤

1、导入http模块

import http from '@ohos.net.http';

2、创建HTTP请求实例,生成HttpRequest对象

let httpRequest = http.createHttp();

注意:每一个httpRequest对应一个http请求任务,不可以复用

3、订阅HTTP响应头(可选)

4、根据URL地址,发起HTTP网络请求

5、处理HTTP响应头和HTTP网络请求的返回结果(可选)

  1. // 导入模块
  2. import http from '@ohos.net.http';
  3. @Entry
  4. @Component
  5. struct HttpTest {
  6. url: string = 'https://mock.apifox.com/m1/3690335-0-default/getHot'
  7. @State titles: string[] = [];
  8. build() {
  9. Row() {
  10. Column() {
  11. Button('获取数据')
  12. .width('50%')
  13. .margin({bottom: 15})
  14. .onClick(() => {
  15. // 创建请求对象
  16. let httpReq = http.createHttp();
  17. // 发起请求
  18. httpReq.request(this.url,{
  19. method: http.RequestMethod.GET,
  20. }, (err,data) => {
  21. // 处理结果
  22. if(!err) {
  23. // this.titles = JSON.parse(`${data}`).values['title']
  24. let arr = JSON.parse(`${data.result}`).values
  25. for(let item of arr) {
  26. this.titles.push(item['title']);
  27. }
  28. }
  29. })
  30. })
  31. ForEach(this.titles, (item) =>{
  32. Text(item)
  33. .fontSize(14)
  34. .margin({bottom:5})
  35. },item => item)
  36. }
  37. .width('100%')
  38. }
  39. .height('100%')
  40. }
  41. }

6.2.3、http请求-Promise方式

使用这种方式是为了避免地狱回调的问题。

  1. // 导入模块
  2. import http from '@ohos.net.http';
  3. @Entry
  4. @Component
  5. struct HttpPromiseTest {
  6. url: string = 'https://mock.apifox.com/m1/3690335-0-default/getHot'
  7. @State titles: string[] = [];
  8. build() {
  9. Row() {
  10. Column() {
  11. Button('获取数据')
  12. .width('50%')
  13. .margin({bottom: 15})
  14. .onClick(() => {
  15. // 创建http请求
  16. let httpReq = http.createHttp();
  17. // 发起请求
  18. let promise = httpReq.request(this.url)
  19. promise.then((data) => {
  20. let arr = JSON.parse(`${data.result}`).values
  21. for(let item of arr) {
  22. this.titles.push(item['title']);
  23. }
  24. })
  25. })
  26. ForEach(this.titles, (item) =>{
  27. Text(item)
  28. .fontSize(14)
  29. .margin({bottom:5})
  30. },item => item)
  31. }
  32. .width('100%')
  33. }
  34. .height('100%')
  35. }
  36. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/280030
推荐阅读
相关标签
  

闽ICP备14008679号