【每日学点HarmonyOS Next知识】网页获取高度、行为菜单底部布局、动画问题、Web跨域加载图片、不随系统深色变化

发布于:2025-03-09 ⋅ 阅读:(18) ⋅ 点赞:(0)

【每日学点HarmonyOS Next知识】网页获取高度、行为菜单底部布局、动画问题、Web跨域加载图片、不随系统深色变化

1、HarmonyOS Web控件getPageHeight()获取高度方法与网页实际高度不一样?

在Web的onPageEnd()方法中调用 getWebViewController().getPageHeight() 获取的高度与网页内容实际高度不符偏小,通过 setTimeout(()=>{ let webHeight1 = this.controller.getWebViewController().getPageHeight() Logger.getInstance().error(‘内部控件高度time’,’ webHeight:‘+webHeight1+’ webHeight:'+vp2px(webHeight1)) },200) 获取的高度与网页实际高度相同,有没有不需要延时的获取网页实际高度的方法?

onPageEnd是页面加载完回调,不等于页面渲染完成,所以前后获取的高度不一样。可使用:onFirstMeaningfulPaint文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-web-V5#ZH-CN_TOPIC_0000001847049744__onfirstmeaningfulpaint12

2、HarmonyOS promptAction.showActionMenu 接口支持布局为底部布局吗?

promptAction.showActionMenu接口支持弹窗布局为底部布局吗?看了下文档里不能设置对其方式,并且示例里也是居中的方式。

参考demo:

import promptAction from '@ohos.promptAction';
import { BusinessError } from '@ohos.base';

function showActionMenu() {
  try {
    promptAction.showActionMenu({
      title: 'Title Info',
      buttons: [
        {
          text: 'item1',
          color: '#666666'
        },
        {
          text: 'item2',
          color: '#000000'
        },
      ]
    }, (err, data) => {
      if (err) {
        console.info('showActionMenu err: ' + err);
        return;
      }
      console.info('showActionMenu success callback, click button: ' + data.index);
    })
  } catch (error) {
    let message = (error as BusinessError).message
    let code = (error as BusinessError).code
    console.error(`showActionMenu args error code is ${code}, message is ${message}`);
  }
  ;
}

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    RelativeContainer() {
      Text(this.message)
        .id('HelloWorld')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .onClick(()=>{
          showActionMenu()
        })
    }
    .height('100%')
    .width('100%')
  }
}
3、HarmonyOS 动画必须搭配@State修饰的变量才能生效吗?

一般情况下动画是需要搭配@State修饰的变量才能生效,以下demo加上 Text().width(300).height(300).backgroundColor(Color.Black)就可以做动画了

@Entry
@Component
export default struct ParticleStar {
  aboutToAppear(): void {
  }

  build() {
    Stack() {
      Text()
        .width(300).height(300).backgroundColor(Color.Black)
      Particle({
        particles: [
          {
            emitter: {
              particle: {
                type: ParticleType.POINT, //粒子类型
                config: {
                  radius: 10//圆点半径
                },
                count: 500, //粒子总数
                lifetime: 10000//粒子生命周期,单位ms
              },
              emitRate: 10, //每秒发射粒子数
              position: [200, 0],
              shape: ParticleEmitterShape.RECTANGLE//发射器形状
            },
            color: {
              range: [Color.Red, Color.Yellow], //初始颜色范围
              updater: {
                type: ParticleUpdater.CURVE, //变化方式为曲线变化
                config: [
                  {
                    from: Color.White, //变化起始值
                    to: Color.Pink, //变化终点值
                    startMillis: 0, //开始时间
                    endMillis: 3000, //结束时间
                    curve: Curve.EaseIn//变化曲线
                  },
                  {
                    from: Color.Pink,
                    to: Color.Orange,
                    startMillis: 3000,
                    endMillis: 5000,
                    curve: Curve.EaseIn
                  },
                  {
                    from: Color.Orange,
                    to: Color.Pink,
                    startMillis: 5000,
                    endMillis: 8000,
                    curve: Curve.EaseIn
                  },
                ]
              }
            },
            opacity: {
              range: [0.0, 1.0], //粒子透明度的初始值从【0.0到1.0】随机产生
              updater: {
                type: ParticleUpdater.CURVE, //透明度的变化方式是随机变化
                config: [
                  {
                    from: 0.0,
                    to: 1.0,
                    startMillis: 0,
                    endMillis: 3000,
                    curve: Curve.EaseIn
                  },
                  {
                    from: 1.0,
                    to: 0.0,
                    startMillis: 5000,
                    endMillis: 10000,
                    curve: Curve.EaseIn
                  }
                ]
              }
            },
            scale: {
              range: [0.0, 0.0],
              updater: {
                type: ParticleUpdater.CURVE,
                config: [
                  {
                    from: 0.0,
                    to: 0.5,
                    startMillis: 0,
                    endMillis: 3000,
                    curve: Curve.EaseIn
                  }
                ]
              }
            },
            acceleration: {
              //加速度的配置,从大小和方向两个维度变化,speed表示加速度大小,angle表示加速度方向
              speed: {
                range: [3, 9],
                updater: {
                  type: ParticleUpdater.RANDOM,
                  config: [1, 20]
                }
              },
              angle: {
                range: [90, 90]
              }
            }
          }
        ]
      }).width(300).height(300)
    }.width("100%").height("100%").align(Alignment.Center)
  }
}
4、HarmonyOS Web组件无法跨域加载图片资源?

App访问网页,网页里面有些图片需要跨域加载,但是因为跨域无法加载显示,请问有什么方法可以解决吗?

跨域请参考以下链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/web-cross-origin-V5

为了提高安全性,ArkWeb内核不允许file协议或者resource协议访问URL上下文中来自跨域的请求。因此,在使用Web组件加载本地离线资源的时候,Web组件会拦截file协议和resource协议的跨域访问。可以通过方法二设置一个路径列表,再使用file协议访问该路径列表中的资源,允许跨域访问本地文件。当Web组件无法访问本地跨域资源时,开发者可以在DevTools控制台中看到类似以下报错信息:

Access to script at 'xxx' from origin 'xxx' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, arkweb, data, chrome-extension, chrome, https, chrome-untrusted.

方法一
为了使Web组件能够成功访问跨域资源,开发者应采用http或https等协议,替代原先使用的file或resource协议进行加载。其中,替代的url域名为自定义构造的仅供个人或者组织使用的域名,以避免与互联网上实际存在的域名产生冲突。同时,开发者需利用Web组件的onInterceptRequest方法,对本地资源进行拦截和相应的替换。

以下结合示例说明如何解决本地资源跨域访问失败的问题。其中,index.html和js/script.js置于工程中的rawfile目录下。如果使用resource协议访问index.html,js/script.js将因跨域而被拦截,无法加载。在示例中,使用https://www.example.com/域名替换了原本的resource协议,同时利用onInterceptRequest接口替换资源,使得js/script.js可以成功加载,从而解决了跨域拦截的问题。

方法二

通过setPathAllowingUniversalAccess设置一个路径列表。当使用file协议访问该列表中的资源时,允许进行跨域访问本地文件。此外,一旦设置了路径列表,file协议将仅限于访问列表内的资源(此时,fileAccess的行为将会被此接口行为覆盖)。路径列表中的路径必须符合以下任一路径格式:

  1. 应用文件目录通过Context.filesDir获取,其子目录示例如下:
    • /data/storage/el2/base/files/example
    • /data/storage/el2/base/haps/entry/files/example
  2. 应用资源目录通过Context.resourceDir获取,其子目录示例如下:
    • /data/storage/el1/bundle/entry/resource/resfile
    • /data/storage/el1/bundle/entry/resource/resfile/example
      当路径列表中的任一路径不满足上述条件时,系统将抛出异常码401,并判定路径列表设置失败。若设置的路径列表为空,file协议的可访问范围将遵循fileAccess的规则,具体示例如下。
// main/ets/pages/Index.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebComponent {
  controller: WebviewController = new webview.WebviewController();

  build() {
    Row() {
      Web({ src: "", controller: this.controller })
        .onControllerAttached(() => {
          try {
            // 设置允许可以跨域访问的路径列表
            this.controller.setPathAllowingUniversalAccess([
              getContext().resourceDir,
              getContext().filesDir + "/example"
            ])
            this.controller.loadUrl("file://" + getContext().resourceDir + "/index.html")
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as   BusinessError).message}`);
          }
        })
        .javaScriptAccess(true)
        .fileAccess(true)
        .domStorageAccess(true)
    }
  }
}
<!-- main/resource/rawfile/index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no,   viewport-fit=cover">
    <script>
        function getFile() {
            var file = "file:///data/storage/el1/bundle/entry/resources/resfile/js/script.js";
      // 使用file协议通过XMLHttpRequest跨域访问本地js文件。
            var xmlHttpReq = new XMLHttpRequest();
            xmlHttpReq.onreadystatechange = function(){
                console.log("readyState:" + xmlHttpReq.readyState);
                console.log("status:" + xmlHttpReq.status);
                if(xmlHttpReq.readyState == 4){
                    if (xmlHttpReq.status == 200) {
                // 如果ets侧正确设置路径列表,则此处能正常获取资源
                        const element = document.getElementById('text');
                        element.textContent = "load " + file + " success";
                    } else {
                // 如果ets侧不设置路径列表,则此处会触发CORS跨域检查错误
                        const element = document.getElementById('text');
                        element.textContent = "load " + file + " failed";
                    }
                }
            }
            xmlHttpReq.open("GET", file);
            xmlHttpReq.send(null);
        }
    </script>
</head>

<body>
<div class="page">
    <button id="example" onclick="getFile()">stealFile</button>
</div>
<div id="text"></div>
</body>

</html>
// main/resources/rawfile/js/script.js
const body = document.body;
const element = document.createElement('div');
element.textContent = 'success';
body.appendChild(element);
5、HarmonyOS 有没有不随系统深色模式变化的操作?

应用主动设置深浅色模式,可参考官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-light-dark-color-adaptation-V5