在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解

一、Web-view 简介

Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面:

  • 支持加载本地 HTML 文件
  • 支持加载远程 HTML 页面
  • 实现 Web 与原生的双向通讯
  • 可用于嵌入第三方网页或 H5 应用
二、Web-view 加载 HTML 的方式
1. 加载本地 HTML 文件
vue 复制代码
<template>
  <view>
    <web-view :src="localHtmlPath"></web-view>
  </view>
</template>

<script setup>
import { ref, onLoad } from 'vue';

const localHtmlPath = ref('');

onLoad(() => {
  // 本地 HTML 文件路径
  localHtmlPath.value = '/static/html/index.html';
});
</script>
2. 加载远程 HTML 页面
vue 复制代码
<template>
  <view>
    <web-view :src="remoteUrl"></web-view>
  </view>
</template>

<script setup>
import { ref, onLoad } from 'vue';

const remoteUrl = ref('');

onLoad(() => {
  // 远程 HTML 页面 URL
  remoteUrl.value = 'https://www.example.com';
});
</script>
三、Web-view 与 Vue 页面的通讯方式
1. H5 页面向 uni-app 发送消息

在 H5 页面中:

javascript 复制代码
// H5 页面 (index.html)
function sendMessageToUniApp() {
  // 方式一:使用 postMessage (推荐)
  window.uni.postMessage({
    type: 'getData',
    data: {
      name: '张三',
      age: 25
    }
  });
  
  // 方式二:使用自定义 JSBridge (兼容旧版本)
  if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.uni) {
    // iOS 平台
    window.webkit.messageHandlers.uni.postMessage({
      type: 'getData',
      data: {
        name: '张三',
        age: 25
      }
    });
  } else if (window.uni) {
    // Android 平台
    window.uni.postMessage(JSON.stringify({
      type: 'getData',
      data: {
        name: '张三',
        age: 25
      }
    }));
  }
}

在 uni-app 页面中接收消息:

vue 复制代码
<template>
  <view>
    <web-view :src="htmlPath" @message="handleMessage"></web-view>
  </view>
</template>

<script setup>
import { ref } from 'vue';

const htmlPath = ref('/static/html/index.html');

const handleMessage = (e) => {
  const data = e.detail.data[0];
  console.log('收到 H5 消息:', data);
  
  // 根据消息类型处理
  if (data.type === 'getData') {
    // 处理数据
    console.log('用户信息:', data.data);
  }
};
</script>
2. uni-app 向 H5 页面发送消息

在 uni-app 页面中:

vue 复制代码
<template>
  <view>
    <button @click="sendToH5">向 H5 发送消息</button>
    <web-view ref="webviewRef" :src="htmlPath"></web-view>
  </view>
</template>

<script setup>
import { ref } from 'vue';

const webviewRef = ref(null);
const htmlPath = ref('/static/html/index.html');

const sendToH5 = () => {
  // 向 H5 发送消息
  webviewRef.value.postMessage({
    type: 'setData',
    data: {
      title: '来自 uni-app 的数据',
      content: '这是一条从 uni-app 发送到 H5 的消息'
    }
  });
};
</script>

在 H5 页面中接收消息:

javascript 复制代码
// H5 页面 (index.html)
// 监听 uni-app 发送的消息
window.addEventListener('message', (e) => {
  const data = e.data;
  console.log('收到 uni-app 消息:', data);
  
  // 根据消息类型处理
  if (data.type === 'setData') {
    // 更新页面内容
    document.getElementById('title').innerText = data.data.title;
    document.getElementById('content').innerText = data.data.content;
  }
});
四、在 H5 页面中调用 uni-app API
1. 使用 postMessage 间接调用

在 H5 页面中:

javascript 复制代码
// H5 页面 (index.html)
function callUniAppAPI() {
  // 请求调用 uni-app API
  window.uni.postMessage({
    type: 'callAPI',
    apiName: 'getLocation',
    params: {
      type: 'wgs84'
    }
  });
}

在 uni-app 页面中:

vue 复制代码
<template>
  <view>
    <web-view :src="htmlPath" @message="handleMessage"></web-view>
  </view>
</template>

<script setup>
import { ref } from 'vue';

const htmlPath = ref('/static/html/index.html');
const webviewRef = ref(null);

const handleMessage = (e) => {
  const data = e.detail.data[0];
  
  // 处理 API 调用请求
  if (data.type === 'callAPI') {
    const { apiName, params } = data;
    
    // 根据 API 名称调用相应的 uni-app API
    if (apiName === 'getLocation') {
      uni.getLocation({
        ...params,
        success: (res) => {
          // 将结果返回给 H5 页面
          webviewRef.value.postMessage({
            type: 'apiResult',
            apiName,
            success: true,
            result: res
          });
        },
        fail: (err) => {
          // 将错误返回给 H5 页面
          webviewRef.value.postMessage({
            type: 'apiResult',
            apiName,
            success: false,
            error: err
          });
        }
      });
    }
    // 可以添加更多 API 的处理
  }
};
</script>

在 H5 页面中接收 API 结果:

javascript 复制代码
// H5 页面 (index.html)
window.addEventListener('message', (e) => {
  const data = e.data;
  
  // 处理 API 调用结果
  if (data.type === 'apiResult') {
    if (data.success) {
      console.log('API 调用成功:', data.result);
      // 更新页面显示
      document.getElementById('location').innerText = `纬度: ${data.result.latitude}, 经度: ${data.result.longitude}`;
    } else {
      console.error('API 调用失败:', data.error);
      // 显示错误信息
      document.getElementById('location').innerText = '获取位置失败';
    }
  }
});
2. 使用 JSBridge 直接调用

在 uni-app 页面中注入 JSBridge:

vue 复制代码
<template>
  <view>
    <web-view ref="webviewRef" :src="htmlPath" @message="handleMessage"></web-view>
  </view>
</template>

<script setup>
import { ref, onReady } from 'vue';

const webviewRef = ref(null);
const htmlPath = ref('/static/html/index.html');

onReady(() => {
  // 注入 JSBridge
  const jsStr = `
    window.uniAPI = {
      getLocation: function(callback) {
        window.uni.postMessage({
          type: 'callAPI',
          apiName: 'getLocation',
          callbackId: 'getLocation_' + Date.now()
        });
        
        // 存储回调函数
        window.uniAPI._callbacks['getLocation_' + Date.now()] = callback;
      },
      _callbacks: {}
    };
  `;
  
  // 执行 JS 代码注入 JSBridge
  webviewRef.value.evalJs(jsStr);
});

const handleMessage = (e) => {
  const data = e.detail.data[0];
  
  // 处理 API 调用结果
  if (data.type === 'apiResult') {
    const callback = window.uniAPI._callbacks[data.callbackId];
    if (callback) {
      callback(data.success ? data.result : null, data.success ? null : data.error);
      delete window.uniAPI._callbacks[data.callbackId];
    }
  }
};
</script>

在 H5 页面中使用 JSBridge:

javascript 复制代码
// H5 页面 (index.html)
function getLocation() {
  // 使用 JSBridge 调用 uni-app API
  window.uniAPI.getLocation((result, error) => {
    if (result) {
      console.log('获取位置成功:', result);
      document.getElementById('location').innerText = `纬度: ${result.latitude}, 经度: ${result.longitude}`;
    } else {
      console.error('获取位置失败:', error);
      document.getElementById('location').innerText = '获取位置失败';
    }
  });
}
五、注意事项与最佳实践
  1. 跨域问题

    • 加载远程 HTML 时需确保域名在白名单中
    • manifest.json 中配置 h5domains
  2. 性能优化

    • 避免频繁通讯
    • 使用批量数据传输
    • 对数据进行压缩处理
  3. 安全考虑

    • 验证消息来源
    • 对敏感操作进行权限控制
    • 避免在 URL 中传递敏感信息
  4. 兼容性处理

    • 处理不同平台的差异
    • 提供降级方案
    • 进行充分测试
  5. 调试技巧

    • 使用 HBuilderX 的调试工具
    • 在 H5 页面中添加日志输出
    • 使用浏览器开发者工具调试
六、常见问题解决方案
  1. 消息接收不及时

    • 确保 web-view 组件已加载完成
    • 使用定时器重试机制
  2. API 调用失败

    • 检查 API 名称和参数是否正确
    • 确认 API 权限是否已获取
    • 处理 API 调用超时情况
  3. 内存泄漏

    • 及时清理不再使用的回调函数
    • 避免创建过多的临时对象
    • 合理管理消息队列
  4. 性能问题

    • 减少跨边界通讯次数
    • 批量处理数据
    • 对大数据进行分片传输

通过以上方法,您可以在 uni-app 中实现 Web-view 与 Vue 页面的高效通讯,为用户提供更丰富的交互体验。

相关推荐
weixin_382395235 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__5 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.6 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~7 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华7 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子10 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅10 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni10 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学11 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端