HarmonyOS 鸿蒙Next客户端适配问题

HarmonyOS 鸿蒙Next客户端适配问题

本人前端开发,目前在配合企业app鸿蒙版做适配,属于客户端内嵌H5,最近在鸿蒙客户端上发现一些样式问题,H5页面里如果采用rem为像素单位时会出现样式没生效的效果,改为px则样式正常展示,但rem在ios和android都正常展示的,应该不存在H5页面根元素未定义的问题,想过改为px,但涉及更改页面量很大,需要大量回归测试,不现实,跟鸿蒙客户端开发人员沟通过,得到的反馈也是不知道咋解决,想问下大家在开发中遇到这种问题吗。harmonyOS NEXT版本是5.0.1

3 回复

【背景知识】

  • textZoomRatio 属性在 Web 组件中用于设置文本的缩放比例。这个属性允许开发者指定网页文本内容的放大或缩小程度,这对于改善用户体验或者满足特定的视觉需求非常有用。
  • runJavaScript:异步执行 JavaScript 脚本,并通过回调方式返回脚本执行的结果。runJavaScript 需要在 loadUrl 完成后,比如 onPageEnd 中调用。
  • rem:CSS 中的相对长度单位(相对于 HTML 根元素的字体大小),通过修改 HTML 根元素的字体大小,实现等比例缩放。
  • display.on(‘foldDisplayModeChange’):开启折叠设备屏幕显示模式变化的监听。

【解决方案】

  • 文本和图片等比例缩放:

    • 文本缩放:设置 Web 组件的 textZoomRatio 属性缩放文本。

    • 图片缩放:若所有需要缩放的图片有相同的 CSS 类名,可采用 runJavaScript 注入或修改该类的宽高样式,示例代码:

      import { webview } from '[@kit](/user/kit).ArkWeb';
      
      [@Entry](/user/Entry)
      [@Component](/user/Component)
      struct Index {
        url: string = 'https://weixin.sxyygh.com/harmony/index.html#/'
      
        private webviewController: WebviewController = new webview.WebviewController()
        private customStyle: string = '.weex-ct{border:5px solid black}';
      
        onBackPress() {
          // 当前页面是否可前进或者后退给定的 step 步 (-1),正数代表前进,负数代表后退
          if (this.webviewController.accessStep(-1)) {
            this.webviewController.backward(); // 返回上一个 web 页
            // 执行用户自定义返回逻辑
            return true
          } else {
            // 执行系统默认返回逻辑,返回上一个 page 页
            return false
          }
        }
      
        build() {
          Column() {
            Button('style').onClick(event => {
              // 可以在 onPageEnd 调用该方法注入 css 样式
              this.webviewController.runJavaScript(`
                const head = document.head;
                console.log(head);
                const style = document.createElement('style');
                style.appendChild(document.createTextNode("${this.customStyle}"));
                head.appendChild(style)
              `);
            })
            Web({
              src: this.url,
              controller: this.webviewController,
            })
              .fileAccess(true)
              .javaScriptAccess(true)
              .domStorageAccess(true)
              .onlineImageAccess(true)
              .mixedMode(MixedMode.All)
              .textZoomRatio(50) // 要设置的页面的文本缩放百分比。取值为整数,范围为(0,+∞)。默认值:100。
              .onPageEnd(e => { // 对所有长宽相等的 weex-image 缩放到 80%
                this.controller.runJavaScript(`
                  let weexImages = document.getElementsByClassName('weex-image');
                  for (let i = 0; i < weexImages.length; i++) {
                    if (weexImages[i].style.width === weexImages[i].style.height) {
                      let newLength = parseFloat(weexImages[i].style.width) * 0.8 + 'rem';
                      weexImages[i].style.width = newLength;
                      weexImages[i].style.height = newLength;
                    }
                  }
                `)
              })
          }
          .width('100%')
          .height('100%')
        }
      }
      
  • 布局响应折叠设备屏幕显示模式变化:在折叠状态改变时,根据屏幕宽度变化,等比例修改 H5 页面根元素的字体大小(fontSize)即可。示例代码:

    import { webview } from '[@kit](/user/kit).ArkWeb';
    import { display } from '[@kit](/user/kit).ArkUI';
    
    [@Entry](/user/Entry)
    [@Component](/user/Component)
    struct Index {
      controller: webview.WebviewController = new webview.WebviewController()
      // 记录当前屏幕宽度
      private lastScreenWidth: number = display.getDefaultDisplaySync().width
    
      aboutToAppear(): void {
        // 监听折叠设备屏幕显示模式变化
        display.on('foldDisplayModeChange', (data: display.FoldDisplayMode) => {
          // 获取折叠设备屏幕显示模式变化后的屏幕宽度,计算出与变化前的屏幕宽度的比值,等比例改变 HTML 根元素字体大小
          const currentWidth = display.getDefaultDisplaySync().width
          const ratio = currentWidth / this.lastScreenWidth
          this.controller.runJavaScript(`
            document.documentElement.style.fontSize = parseFloat(document.documentElement.style.fontSize) * ${ratio} + 'px'
          `)
          // 更新当前屏幕宽度
          this.lastScreenWidth = currentWidth
        });
      }
    
      build() {
        RelativeContainer() {
          Web({
            src: 'https://www.example.com',
            controller: this.controller
          })
            .domStorageAccess(true)
            .mixedMode(MixedMode.All)
            .onlineImageAccess(true)
        }
        .height('100%')
        .width('100%')
      }
    }
    

【常见FAQ】

Q:既然 H5 是使用 px 作为长度单位,为什么不通过修改根元素 html 的 fontSize 大小,来改变相同 rem 单位对应的实际像素,从而实现图片和文字的等比例缩放? A:因为这样一来,不仅是文字和图片会等比例缩放,H5 内使用 rem 作为长度单位的元素尺寸、间距等都会改变。weex 中的根元素 html 的 fontSize 大小(即 1rem)=1/10 屏幕宽度,若 1rem 对应的像素值变少,会导致整个页面缩小,无法占满屏幕宽度。

【总结】

小范围或场景比较单一的样式修改可以采用 runJavaScript 注入或修改 CSS 样式,大范围或复杂样式修改的话建议还是在 H5 页面中实现。

更多关于HarmonyOS 鸿蒙Next客户端适配问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next客户端适配主要涉及以下几个方面:

  1. 使用ArkTS语言开发,需遵循新的API规范
  2. UI适配需采用自适应布局和响应式设计
  3. 依赖库需兼容HarmonyOS SDK最新版本
  4. 设备能力调用需使用新的权限管理机制
  5. 应用包结构需符合新的HAP格式要求

需要针对不同设备类型(手机、平板、智慧屏等)进行差异化适配,重点关注API兼容性和性能优化。鸿蒙Next的分布式能力要求应用支持跨设备无缝衔接。

关于HarmonyOS Next中H5页面rem单位失效的问题,这是一个已知的兼容性问题。主要原因在于鸿蒙Next的WebView内核对CSS rem单位的解析存在差异。

建议尝试以下解决方案:

  1. 检查html根元素的font-size设置是否正确,可以尝试显式设置html{font-size:16px!important}
  2. 在页面head中添加viewport meta标签:
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    
  3. 可以尝试在CSS中增加-webkit-前缀:
    html {
      -webkit-text-size-adjust: 100%;
    }
    

如果以上方法无效,可能需要考虑使用postcss插件批量将rem转换为px,这样改动量最小且不需要大量回归测试。

回到顶部