uniapp 小程序 web-view 打开H5页面传参以及调用postMessage回传参数

  • uniapp 运行微信小程序,在小程序内利用 web-view 打开H5页面进行数据流转的总结。

  • 首先做点准备工作,官网明确的说了小程序是不支持本地的,那怎么进行调试呢,这里也简单,我们使用 node.js 起一个本地服务器,然后在 uniapp 中使用。

    • 这里直接把 js 代码贴出来,直接复制就可以了

      const http = require('http');
      const fs = require('fs');
      const path = require('path');
      ​
      function startServer() {
          const server = http.createServer((req, res) => {
              // 设置通用响应头
              res.setHeader('Content-Type', 'text/html; charset=utf-8');
              let stream;
              switch (req.url) {
                  case '/h5.html':
                      // 首页内容
                      filePath = 'h5.html';
                      break;
              }
      ​
              if (filePath) {
                  // 获取文件流
                  stream = fs.createReadStream(path.join(__dirname, filePath), 'utf8');
                  // 监听错误事件
                  stream.on('error', (err) => {
                      console.error('Stream error:', err);
                      // 重写响应头
                      res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
                      res.end('500 Internal Server Error');
                  });
                  stream.pipe(res);
              } else {
                  // 如果没有设置文件路径,发送404响应
                  res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
                  res.end('404 Not Found');
              }
          });
      ​
          server.listen(3000, '127.0.0.1', () => {
              console.log('Server is listening on port 3000');
          });
      }
      ​
      module.exports = { startServer };
      startServer()

  • node本地服务
  • 然后这个地方要注意一下,这里的 html 文件就是一会要在内嵌在小程序中的文件,而且要注意,这个文件要跟 node.js 在同一级文件夹内,然后那个 case 就是我们要访问的路径,运行,出现这个信息就是运行成功了。

uniap 小程序 web-view

  • 这里我们要创建两个文件,index和auto

  • index 文件中代码如下,这里我们写一个按钮然后跳到 auto 然后在auto文件中内嵌H5页面,同时监听 login 事件,拿到 auto 的页面提交的参数。等下会解释为什么这么做。

    <template>
      <view class="content">
        <view class="text-area">
          <text class="title">{{ title }}</text>
        </view>
    ​
        <view>
          <button @click="clickUrl">点击跳转H5</button>
        </view>
    ​
        <view>
          h5页面传过来的参数:{{ paramsH5.userName }} {{ paramsH5.message }}</view
        >
      </view>
    </template>
    ​
    <script>
    export default {
      data() {
        return {
          title: "微信小程序页面1",
          paramsH5: { userName: "", message: "" },
        };
      },
      onLoad() {
        uni.$on("login", (usnerinfo) => {
          this.paramsH5 = usnerinfo;
        });
      },
      onUnload() {
        // 移除监听事件
        uni.$off("login");
      },
      methods: {
        clickUrl(params) {
          uni.navigateTo({
            url: "/pages/auto/index",
          });
        },
      },
    };
    </script>
    <style>
    .content {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }
    ​
    .logo {
      height: 200rpx;
      width: 200rpx;
      margin-top: 200rpx;
      margin-left: auto;
      margin-right: auto;
      margin-bottom: 50rpx;
    }
    ​
    .text-area {
      display: flex;
      justify-content: center;
      margin: 24rpx;
      font-size: 48rpx;
      font-weight: bold;
      color: black;
    }
    ​
    .title {
      font-size: 36rpx;
      color: #8f8f94;
    }
    </style>

  • auto 文件中代码如下,这里的 http://127.0.0.1:3000/h5.html?name=iadajelkljwieqjeojqoi1j231j 就是我们访问H5页面的链接,问号后面就是向H5页面传递的参数。目前网上小程序对H5页面传参数的方法基本都是通过 url 的方法,其他方法需要各位自行查阅了,这里的 @message="handleMessage" 就是拿到H5页面传回来的数据,拿到之后我们通过 uni.$emit 提交到 index 页面展示。

<template>
  <view class="content">
    <web-view
      @load="loadSuccess"
      @error="loadError"
      src="http://127.0.0.1:3000/h5.html?name=iadajelkljwieqjeojqoi1j231j"
      @message="handleMessage"
    ></web-view>
  </view>
</template>
  
  <script>
export default {
  data() {
    return {
      title: "微信小程序页面2",
    };
  },
  onLoad() {},
  methods: {
    handleMessage(data) {
      console.log("接收到的消息:", data.detail.data);
      uni.$emit("login", {
        userName: "unier",
        message: data.detail.data,
      });
    },
​
    loadSuccess() {
      console.log("加载成功");
    },
    loadError() {
      console.log("加载失败");
    },
  },
};
</script>
  
<style>
</style>
  
  • H5页面代码如下,这里要注意,调用完 uni.postMessage({ action: 'someAction', data: 'someData' }) 回传数据后,要调用 uni.navigateBack({ delta: 1 }); 因为官网是这样解释的 ( 会在特定时机(后退、组件销毁、分享)触发并收到消息。 ),所以要调用后退,不然 @message="handleMessage" 无法接收消息,还有 JS-SDK 的引入,这个引入的方法官网都有,我这边是只有微信,所以就只引了微信的,注意引入的顺序,uni sdk 放到body下面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>H5页面</title>
    <style>
        .title {
            font-size: 24px;
            font-weight: bold;
            text-align: center;
        }
​
        .wxParams {
            font-size: 24px;
            font-weight: bold;
            text-align: center;
            margin: 12px;
        }
​
        #paramsText {
            text-align: center;
        }
    </style>
</head>
​
<body>
    <div id="app">
        <h1 class="title">这是一个H5页面</h1>
        <div class="title"><button id="backBtn">传参返回微信小程序</button></div>
​
        <div class="wxParams">小程序页面传过来的参数:</div>
        <div id="paramsText"></div>
    </div>
​
​
    <!-- 微信 JS-SDK 如果不需要兼容小程序,则无需引用此 JS 文件。 -->
    <script type="text/javascript">
        document.write('<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"><\/script>');
    </script>
</body>
    
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
​
​
<script type="text/javascript">
   
    // 获取小程序中传过来的参数并展示
    document.querySelector('#paramsText').innerHTML = getQuery('name')
    function getQuery(name) {
        // 正则:[找寻'&' + 'url参数名字' = '值' + '&']('&'可以不存在)
        let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
        let r = window.location.search.substr(1).match(reg);
        if (r != null) {
            // 对参数值进行解码
            return decodeURIComponent(r[2]);
        }
        return null;
    }
    
    // 待触发 `UniAppJSBridgeReady` 事件后,即可调用 uni 的 API。
    document.addEventListener('UniAppJSBridgeReady', function () {
        console.log('UniAppJSBridgeReady加载完成');
        uni.getEnv(function (res) {
            console.log('当前环境:' + JSON.stringify(res));
        });
​
        document.querySelector('#backBtn').addEventListener('click', function (evt) {
​
            uni.postMessage({ action: 'someAction', data: 'someData' })
            uni.navigateBack({ delta: 1 });
        });
    });
​
​
</script>
​
</html>
  • 最终效果

  • 最后说一下为什么创建两个文件,为什么在auto中通过监听和提交数据的形式拿到H5页面传过来的参数,首先,笔者最开始也是在一个文件中使用web-view组件,但是发现无论怎么做 H5页面 uni.navigateBack({ delta: 1 }) 这行代码就是不生效,,,不生效就无法触发@message,就拿不到H5页面的参数,浪费了好长时间,最后才发现不是不生效,而是在一个页面中没有能 navigateBack 返回的页面,,,,就无法触发@message。

  • 最后分两个文件,这样就能 navigateBack 然后触发 @message 了,也正是因为这样,我们的 auto 中嵌套的H5页面在执行 uni.navigateBack({ delta: 1 }) 这段代码之后,会回到index页面。所以使用监听和提交数据的方式拿到H5页面的数据,这样就能在index文件中展示了。好了,到这里就结束了,记录我的踩坑之旅。

Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐