uni-app开发经验分享-跨端开发经验总结

距离上一次分享uniapp开发经验已经5年了,uni-app开发经验分享- 路由、通信、开发中遇到的问题,今天分享的是uniapp在跨端使用上经验和遇到的坑。

类似于"微前端"技术方案

微前端是 将前端应用拆分为多个独立子应用 ,由一个主应用统一调度、集成、路由联动的架构模式;

pc端成熟的技术方案有:iframe、qiankun、wujie、Module Federation 模块联邦等,我们目前使用的是wujie,关于wujie在下一篇我们再讨论,现在主要讲uniapp如何实现类似的技术。

嵌套webview

以下示例支持非H5端,其中app端webview支持本地网页和远程网页,但本地网页及相关资源(js、css等文件)必须放在 uni-app 项目根目录->hybrid->html 文件夹下或者 static 目录下,而小程序只支持远程网页,且需要在小程序后台配置业务域名,H5端请使用Iframe,通过window.message和window.postMessage

类似于iframe,就是子项目都是H5,主应用通过webview渲染页页面

主应用通过网页链接向子应用传递参数:juejin.cn/post/691934...?id=1&name=demo

子应用获取主应用参数:location.href.split('?').pop(),然后再解析

子应用传递参数给主应用需要以下步骤:

  1. 子应用引入引入uni.web-view.js:gitcode.com/dcloud/uni-...
  2. 子应用通过uni.postmessage 向子应用发送通知
  3. 主应用监听webview的message事件接受子应用参数

以下是代码示例:

vue 复制代码
<template>
  <view>
    <webview ref='web' :src='url' @onPostMessage='handlePostMessage'></webview>
  </view>
</template>
<script>
  export default {
    data() {
      return {
        url: ''
      }
    },
    methods: {
      handlePostMessage(e) {
        uni.showModal({
            content: JSON.stringify(e.detail),
            showCancel: false
	})
      }
    }
  }
</script>
html 复制代码
<!DOCTYPE html>
<html>
  <head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
	</head>
  <body>
    <button type="button" id="postMessage">传递数据给主应用</button>
    <script type="text/javascript" src="https://unpkg.com/@dcloudio/uni-webview-js@0.0.1/index.js"></script>
    <script>
      document.addEventListener('UniAppJSBridgeReady', function() {
        const querystring = location.href.split('?').pop()
        const queryObj = {}
        if (querystring && querystring.length) {
          const qeurySplitArray = querystring.split('&')
          if (qeurySplitArray && qeurySplitArray.length) {
            qeurySplitArray.formEach(item => {
              if (item) {
                const [key, value] = item.split('=')
                queryObj[key] = value || ''
              }
            })
          }
        }
        document.querySelector("#postMessage").addEventListener('click', function() {
					uni.postMessage({
						data: {
							action: 'message'
						}
					});
				})
      })
    </script>
  </body>
</html>

小程序参考资料:developers.weixin.qq.com/miniprogram...

H5端参考资料:developer.mozilla.org/zh-CN/docs/...

uni小程序

我们目前落地的开发方案是原生提供容器,即原生统一处理公共逻辑,并提供各业务应用的入口,然后各业务通过uniapp开发各自的子应用,子应用打包成wgt,原生通过引入uni小程序SDK和各个子应用的wgt进行通信,原生提供公共插件供子应用调用,关于app和wgt通信的方式参考官网文档:nativesupport.dcloud.net.cn/

下面说下,如何将unipp打包为wgt项目

  1. hbuilder编辑器

这个是大家常用的打包模式

  1. vue cli项目通过命令行打包

官方说明使用npm run build:app-plus会在/dist/build/app-plus下生成app打包资源。如需制作wgt包,将app-plus中的文件压缩成zip(注意:不要包含app-plus目录),再重命名为${appid}.wgtappidmanifest.json文件中的appid

我们可以写node版本简化手动操作,根目录下创建build.js文件,以下是示例代码:

js 复制代码
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');
const manifest = require('../src/manifest.json');

// 工具函数:路径解析(提前声明,避免变量提升问题)
const resolve = (dir) => path.resolve(__dirname, dir);

// 配置常量
const APP_ID = manifest.appid;
const SOURCE_DIR = '../dist/build/app-plus';
const OUTPUT_FILE = `../dist/${APP_ID}.wgt`;
const OUTPUT_PATH = resolve(OUTPUT_FILE);

// 创建压缩实例(最高压缩等级)
const archive = archiver('zip', {
  zlib: { level: 9 }
});

// 创建输出流
const output = fs.createWriteStream(OUTPUT_PATH);

// 管道连接
archive.pipe(output);

/**
 * 递归添加目录/文件到压缩包
 * @param {string} dir 源目录
 */
function addFilesToArchive(dir) {
  const absPath = resolve(dir);
  
  // 判断目录是否存在
  if (!fs.existsSync(absPath)) {
    console.error(`❌ 目录不存在:${absPath}`);
    process.exit(1);
  }

  const items = fs.readdirSync(absPath);

  items.forEach(item => {
    const itemPath = path.join(absPath, item);
    const stat = fs.lstatSync(itemPath);

    if (stat.isDirectory()) {
      // 目录:直接添加(保留结构)
      archive.directory(itemPath, item);
    } else if (stat.isFile()) {
      // 文件:流方式添加
      archive.file(itemPath, { name: item });
    }
  });
}

// 事件监听(更完善的成功/失败提示)
output.on('close', () => {
  const size = (archive.pointer() / 1024 / 1024).toFixed(2);
  console.log(`\n✅ 打包完成:${APP_ID}.wgt`);
  console.log(`📦 文件大小:${size} MB`);
  console.log(`📍 输出路径:${OUTPUT_PATH}\n`);
});

archive.on('error', (err) => {
  console.error(`\n❌ 打包失败:${err.message}\n`);
  throw err;
});

// 执行打包
try {
  addFilesToArchive(SOURCE_DIR);
  archive.finalize();
} catch (err) {
  console.error(`\n💥 执行异常:${err.message}\n`);
  process.exit(1);
}
shell 复制代码
{
  "build:wgt": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build && node ./build.js"
}

子应用之前的通信,则通过宿主环境提供方法供子应用使用

微信小程序

我遇到的只要是绘图api兼容问题,比如实现一个水印相机功能,使用uniapp提供的api绘制图片、文字在非小程序端是正常的,但是小程序上就是不展示,api使用上有以下不同:

canvas组件

xml 复制代码
<!-- uniapp -->
<canvas canvas-id="myCanvas" id="myCanvas"></canvas>
<!-- 小程序 -->
<canvas type="2d" id="myCanvas"></canvas>

绘制图片

arduino 复制代码
// uniapp
ctx.drawImage(imagePath, 0, 0, 150, 100)
// 小程序
const image = canvas.createImage()
image.onload = () => {
    ctx.drawImage(image, 0, 0, 150, 100)
}
image.src = imagePath

微信公众号、支付宝生活号

这两端本质上是H5页面,只是为了使用相关平台的api功能需要引入各自的js文件

可以通过以下方法获取浏览器环境

js 复制代码
/**
 * 获取当前浏览器/环境信息(判断微信、企业微信、支付宝、钉钉、小程序)
 * @returns {Object} 环境标识对象
 */
const getChromeEnv = () => {
  // 统一转为小写,只执行一次,提升性能
  const userAgent = navigator.userAgent.toLowerCase();

  return {
    // 微信内置浏览器
    isWechat: /micromessenger/i.test(userAgent),
    
    // 企业微信
    isEnterpriseWechat: /micromessenger/i.test(userAgent) && /wxwork/i.test(userAgent),
    
    // 支付宝
    isAlipay: /alipay/i.test(userAgent),
    
    // 钉钉
    isDingTalk: /dingtalk/i.test(userAgent),
    
    // 微信小程序 WebView
    isWeChatMiniProgram: window?.__wxjs_environment === 'miniprogram'
  };
};

根据对应的环境引入不同的js文件

微信公众号:res2.wx.qq.com/open/js/jwe...

参考文档:developers.weixin.qq.com/doc/subscri...

支付宝生活号:gw.alipayobjects.com/as/g/h5-lib...

相关推荐
我的世界洛天依1 小时前
胡桃讲编程|次元天花板!硬核求解初音未来(Miku)的值|高数 + JS ES262 解构
javascript·ecmascript
阳火锅1 小时前
🔍 别再用 Ctrl+P 了!这才是文件导航的终极解决方案
前端·javascript·vue.js
逆境不可逃2 小时前
Hello-Agents 第二部分-第四章总结:智能体经典范式构建-包含习题解析和Java版
java·开发语言·javascript·人工智能·分布式·agent
yqcoder2 小时前
JavaScript 的速度秘密:深入理解 JIT (即时编译)
开发语言·javascript·ecmascript
西洼工作室2 小时前
UniApp开发全攻略:从生命周期到路由传值
前端·javascript·uni-app
星恒随风2 小时前
四天学完前端基础三件套(JavaScript webAPI篇)
开发语言·前端·javascript
知彼解己2 小时前
从后端视角学习 Vue3:核心知识与数据流实践
javascript·vue.js·ecmascript
天渺工作室2 小时前
Vue自定义指令实现点击事件权限拦截控制的npm插件
前端·vue.js·npm
晓得迷路了2 小时前
栗子前端技术周刊第 129 期 - TanStack npm 供应链入侵事件、pnpm 11.1、Tailwind CSS 4.3...
前端·javascript·css