鸿蒙Next组件Web原生与JS交互(二) 原创 精华

auhgnixgnahz
发布于 2025-8-20 08:58
浏览
0收藏

上篇总结了Web组件的基础属性和事件,这篇通过一个简单案例,学习原生与web的交互。涉及到JS注入,原生调用JS方法,JS调用原生方法。
实现效果
鸿蒙Next组件Web原生与JS交互(二)-鸿蒙开发者社区
实现目标
1.打开目标页面,当有图片或gif预览时,按返回键拦截,关闭预览可以返回到上一页
2.从目标页面跳转到其他页后,按返回键返回到上一页,直到返回目标页时才能退出
实现思路
1.需要给目标web页面注入一个JS方法,监听是否有图片或者gif预览,调试发现,当有预览时,html的body的clss会变成van-overflow-hidden,所以,只需要监听body的class值的变化,就知道当前页面是否有预览。不同的html可能不同,这里只是测试。
2.设置本地接收JS调用的方法,当JS监听到变化时,调用原生Native方法
3.拦截onBackPress返回键方法,判断当前页面是否有预览,如果有则拦截,判断当前页面是否有后退页面,如果有则后退一级,否则退出
实现过程
编写JS注入代码:

// 检查当前是否有打开的图片预览
  function checkImageViewerAndCallNative() {
    let observer = new MutationObserver(mutations => {
      if (mutations?.length) {
        const mutation = mutations[0]
        const currentValue = mutation.target.getAttribute(mutation.attributeName)
        let hasOpenViewer = currentValue === 'van-overflow-hidden'
        nativeJSCallBack.print(hasOpenViewer);
        // 如果存在打开的预览,调用原生方法
        if (hasOpenViewer) {
        nativeJSCallBack.sourcePreview(true);
        }else{
        nativeJSCallBack.sourcePreview(false);
        }
      }
    })
    observer.observe(document.body, {
      attributes: true,
      attributeFilter: ['class'], // 明确指定只监听此属性
      attributeOldValue: true, // 记录旧值用于比对
      subtree: false
    })
  }

原生注册的方法:
1.先定义一个Class,定义供JS调用的方法和参数
2.将定义的JS方法注入到web中
3.调用这个方法
4.页面销毁时取消注册

//定义原生监听js调用的方法
class NativeJSCallBack{
  isPreview:boolean
  constructor() {
    this.isPreview = false
  }
  sourcePreview(preview:boolean):void{
    console.log('NativeJSCallBack: 收到web调用'+preview.valueOf())
    this.isPreview = preview.valueOf()
  }
  print(str:string):void{
    console.log('NativeJSCallBack:'+str)
  }
}
//
// 注册同步函数
 //参数:参与注册的应用侧JavaScript对象,自定义注册对象的名称,参与注册的应用侧JavaScript对象的同步方法
this.webviewController.registerJavaScriptProxy(this.nativeJSCallBack, "nativeJSCallBack", ["sourcePreview","print"]);
this.webviewController.refresh();
//注册js 并调用
this.webviewController.runJavaScript(previewJS)    
this.webviewController.runJavaScript('checkImageViewerAndCallNative()')

全部源码

import ApiConstants from '../net/ApiConstants'
import { webview } from '@kit.ArkWeb'

let previewJS:string = ' // 检查当前是否有打开的图片预览\n' +
  '  function checkImageViewerAndCallNative() {\n' +
  '    let observer = new MutationObserver(mutations => {\n' +
  '      if (mutations?.length) {\n' +
  '        const mutation = mutations[0]\n' +
  '        const currentValue = mutation.target.getAttribute(mutation.attributeName)\n' +
  '        let hasOpenViewer = currentValue === \'van-overflow-hidden\'\n' +
  '        nativeJSCallBack.print(hasOpenViewer);\n' +
  '        // 如果存在打开的预览,调用原生方法\n' +
  '        if (hasOpenViewer) {\n' +
  '        nativeJSCallBack.sourcePreview(true);\n' +
  '        }else{\n' +
  '        nativeJSCallBack.sourcePreview(false);\n' +
  '        }\n' +
  '      }\n' +
  '    })\n' +
  '    observer.observe(document.body, {\n' +
  '      attributes: true,\n' +
  '      attributeFilter: [\'class\'], // 明确指定只监听此属性\n' +
  '      attributeOldValue: true, // 记录旧值用于比对\n' +
  '      subtree: false\n' +
  '    })\n' +
  '  }'

class NativeJSCallBack{
  isPreview:boolean
  constructor() {
    this.isPreview = false
  }
  sourcePreview(preview:boolean):void{
    console.log('NativeJSCallBack: 收到web调用'+preview.valueOf())
    this.isPreview = preview.valueOf()
  }
  print(str:string):void{
    console.log('NativeJSCallBack:'+str)
  }
}

@Entry
@ComponentV2
struct WebViewTest {
  private webviewController: WebviewController = new webview.WebviewController()
  @Local nativeJSCallBack:NativeJSCallBack = new NativeJSCallBack()
  build() {
    Column() {
      Web({
        src: ApiConstants.WEB_URL,
        controller: this.webviewController,
        renderMode: RenderMode.ASYNC_RENDER // 设置渲染模式
      })//Web组件网页正常加载过程所涉及的状态
        //该回调调用时网页还未加载,因此无法在回调中使用有关操作网页的接口
        .onControllerAttached(() => {
          // 推荐在此loadUrl、设置自定义用户代理、注入JS对象等
          console.log('onControllerAttached execute')
          // 注册同步函数
          //参数:参与注册的应用侧JavaScript对象,自定义注册对象的名称,参与注册的应用侧JavaScript对象的同步方法
          this.webviewController.registerJavaScriptProxy(this.nativeJSCallBack, "nativeJSCallBack", ["sourcePreview","print"]);
          this.webviewController.refresh();
        })
        .onPageEnd((event) => {
          // 推荐在此事件中执行JavaScript脚本
          if (event) {
            console.log('onPageEnd url:' + event.url);
          }
          this.webviewController.runJavaScript(previewJS)
          this.webviewController.runJavaScript('checkImageViewerAndCallNative()')
        })
          //组件卸载消失时触发此回调
        .onDisAppear(() => {
          this.webviewController.deleteJavaScriptRegister("nativeJSCallBack");
        })
    }
  }
  onBackPress(): boolean | void {
    if (this.nativeJSCallBack.isPreview) {
      return true
    }
    if (this.webviewController.accessBackward()) {
      this.webviewController.backward()
      return true
    }
    return false
  }
}

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
标签
2
收藏
回复
举报
回复
    相关推荐