HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

如何在uni-app 平台快速实现一对一音视频通话应用

uniapp 教程

“一套代码,多端运行”是很多开发团队的梦想。ZEGO SDK基于uni-app跨平台框架支持iOS、Android、Windows、macOS、HarmonyOS、Web、小程序并支持平台间互通,快速实现搭建多端音视频通话,大大降低开发和学习成本。

本文将引导快速创建和运行第一个uni-app RTC项目,适合想要快速完成多端共用音视频项目的开发者;

1 准备环境

在开始集成 ZEGO Express SDK 前,请确保开发环境满足以下要求:
HBuilderX 3.0.0 或以上版本。
准备 iOS / Android 设备,版本要求如下:
iOS 9.0 或以上版本且支持音视频的 iOS 设备。
Android 4.4 或以上版本且支持音视频的 Android 设备。
iOS / Android 设备已经连接到 Internet。

2 项目准备

2.1 创建项目

进入即构官网,在控制台创建项目,并申请有效的 AppID,这一步很关键,appid为应用的唯一标识,如身份证号,是应用的身份证明,用于明确你的项目及组织身份。zego提供的服务也是基于APP ID;

App ID的获取方式很简单,只需3~5分钟,在即构官网-我的项目-创建即可。创建的项目信息可用于SDK的集成和配置;

2.2 Token 鉴权

登录房间时必须 使用 Token 鉴权 ,可参考 Token 鉴权教程
为了方便开发阶段的调试,开发者可直接在 ZEGO 控制台获取临时 Token(有效期为 24 小时) 来使用,详情请参考 控制台(新版) - 项目管理 中的 “项目信息”。

3 集成

3.1 项目设置

开始集成前,可参考如下步骤设置你的项目;
如已有项目,本步骤可忽略。
如需新建项目,可按照以下步骤创建你的新项目:

1.启动 HBuilderX,选择“文件 > 新建 > 项目”菜单。

2.在出现的表单中,选择 “uni-app” 平台,并填写项目名称。

3.单击“创建”,即可创建项目。

3.2 导入 SDK

在 ZEGO 官网下载 SDK

1.下载 Express-Video SDK 到本地,解压缩 “zego-ZegoExpressUniAppSDK” 文件。

2.将解压缩后的文件夹直接复制到项目工程根目录下的 “nativeplugins” 文件夹,如果没有该目录,请手动创建。

3.3 在 uni-app 项目中导入插件

1.单击项目目录的 “manifest.json” 文件后,单击“App原生插件配置”中的“选择本地插件”或“选择云端插件”。

2.在弹出的选择框中,选择 “ZegoExpress 音视频 SDK” 后,单击“确认”,即添加成功。

3.4 自定义调试基座

3.4.1 制作自定义调试基座
1.选择“运行 > 运行到手机或模拟器 > 制作自定义调试基座”菜单。

2.在弹出的界面中,按照 uni-app 教程,填写相关信息,并单击“打包”进行云打包。

打包成功后,控制台会收到 uni-app 的相关提示。

3.4.2 切换运行基座为自定义调试基座
自定义调试基座选择“运行 > 运行到手机或模拟器 > 运行基座选择 > 自定义调试基座”菜单。

4 集成 JS 封装层

1.导入 JS 封装层。

在插件市场的 ZegoExpressEngine 音视频插件(JS) 界面单击右侧的“使用 HBuilderX导入插件”。

导入的 JS 封装层将存储在 “components” 目录中。

2.导入后可以在业务代码中引入 JS 封装层,并调用 Express 相关接口,示例如下:

import ZegoExpressEngine from '@/components/zego-ZegoExpressUniApp-JS/lib/ZegoExpressEngine';

5 实现流程

用户通过 ZEGO Express SDK 进行视频通话的基本流程为:
用户 A、B 加入房间,用户 B 预览并将音视频流推送到 ZEGO 云服务(推流),用户 A 收到用户 B 推送音视频流的通知之后,在通知中播放用户 B 的音视频流(拉流)。

整个音视频通话推拉流过程的 API 调用时序如下图:

5.1 创建引擎

1. 创建界面

在创建引擎之前,ZEGO 推荐开发者添加以下界面元素,方便实现基本的实时音视频功能。

本地预览窗口
远端视频窗口
结束按钮

2. 创建引擎

调用 createEngineWithProfile 接口,将申请到的 AppID 传入参数 “appID”,创建引擎单例对象。
如果需要注册回调方法,开发者可根据实际需要,实现 ZegoEventListener 中的某些方法,创建引擎后可通过调用 on 接口设置回调。
// 导入
import ZegoExpressEngine from '@/components/zego-ZegoExpressUniApp-JS/lib/ZegoExpressEngine';

// 采用通用场景
const profile = {
appID : xxx,
scenario : 0
};

ZegoExpressEngine.createEngineWithProfile(profile)

5.2 登录房间

1. 登录

你可以调用 loginRoom 接口登录房间。roomID 和 user 的参数由您本地生成,但是需要满足以下条件:

同一个 AppID 内,需保证 “roomID” 全局唯一。
同一个 AppID 内,需保证 “userID” 全局唯一,建议开发者将 “userID” 与自己业务的账号系统进行关联。

let roomConfig = {};
//token 由用户自己的服务端生成,为了更快跑通流程,也可以通过即构控制台获取临时的音视频 token
roomConfig.token = "xxxx";
// 只有传入 “isUserStatusNotify” 参数取值为 “true” 的 ZegoRoomConfig,才能收到 onRoomUserUpdate 回调。
roomConfig.isUserStatusNotify = true;
// 登录房间
// 开始登录房间
ZegoExpressEngine.instance().loginRoom('room1', {'userID': 'id1', 'userName': 'user1'}, roomConfig);

2. 监听登录房间后的事件回调

可根据实际应用需要,在登录房间后监听想要关注的事件通知,比如房间状态更新、用户状态更新、流状态更新等。

roomStateUpdate:房间状态更新回调,登录房间后,当房间连接状态发生变更(如出现房间断开,登录认证失败等情况),SDK 会通过该回调通知。
roomUserUpdate:用户状态更新回调,登录房间后,当房间内有用户新增或删除时,SDK 会通过该回调通知。
只有调用 loginRoom 接口登录房间时传入 ZegoRoomConfig 配置,且 “isUserStatusNotify”参数取值为 “true” 时,用户才能收到 roomUserUpdate 回调。
roomStreamUpdate:流状态更新回调,登录房间后,当房间内有用户新推送或删除音视频流时,SDK 会通过该回调通知。

// 以下为常用的房间相关回调

ZegoExpressEngine.instance().on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
// 房间状态更新回调,登录房间后,当房间连接状态发生变更(如出现房间断开,登录认证失败等情况),SDK会通过该回调通知
}); ;

ZegoExpressEngine.instance().on('roomUserUpdate', (roomID, updateType, userList) => {
// 用户状态更新,登录房间后,当房间内有用户新增或删除时,SDK会通过该回调通知
});

ZegoExpressEngine.instance().on('roomStreamUpdate', (roomID, updateType, streamList) => {
// 流状态更新,登录房间后,当房间内有用户新推送或删除音视频流时,SDK会通过该回调通知
});

5.3 推流

1. 开始推流

调用 startPublishingStream 接口,传入流 ID 参数 “streamID”,向远端用户发送本端的音视频流。

/* 开始推流 /
ZegoExpressEngine.instance().startPublishingStream("streamID");

2. 启动本地预览

如果希望看到本端画面,可使用 标签设置预览视图,并调用 startPreview 接口启动本地预览。

<template>
<zego-local-view style="height: 403.84rpx;flex: 1;"></zego-local-view>
</template>

js部分:
/* 开始预览 /
ZegoExpressEngine.instance().startPreview()

3. 监听推流后的事件回调

根据实际应用需要,在推流后监听想要关注的事件通知,比如推流状态更新等。
publisherStateUpdate:推流状态更新回调,调用推流接口成功后,当推流状态发生变更,如出现网络中断导致推流异常等情况,SDK 在重试推流的同时,会通过该回调通知。

ZegoExpressEngine.instance().on("publisherStateUpdate", (streamID, state, errorCode, extendedData) => {
// 调用推流接口成功后,当推流器状态发生变更,如出现网络中断导致推流异常等情况,SDK在重试推流的同时,会通过该回调通知
//....
});

5.4 拉流

1. 开始拉流

使用 标签设置远端视频流视图,调用 startPlayingStream 接口,根据传入的流 ID 参数 “streamID”,拉取远端推送的音视频流。
<template>
<zego-remote-view :streamID="playStreamID" style="height: 403.84rpx;flex: 1"></zego-remote-view>
</template>

js部分:
/* 开始拉流 /
this.playStreamID = "StreamID_1"
ZegoExpressEngine.instance().startPlayingStream(this.playStreamID)

  1. 监听拉流后的事件回调
    根据实际应用需要,在拉流后监听想要关注的事件通知,比如拉流状态更新等。
    playerStateUpdate:拉流状态更新回调,调用拉流接口成功后,当拉流状态发生变更,如出现网络中断导致推流异常等情况,SDK 在重试拉流的同时,会通过该回调通知。

ZegoExpressEngine.instance().on("playerStateUpdate", (streamID, state, errorCode, extendedData) => {
/* 调用拉流接口成功后,当拉流器状态发生变更,如出现网络中断导致推流异常等情况,SDK在重试拉流的同时,会通过该回调通知 /
//....
});

5.5 体验实时音视频功能

在真机中运行项目,运行成功后,可以看到本端视频画面。
为方便体验,ZEGO 提供了一个 Web 端调试示例,在该页面下,输入相同的 AppID、RoomID、Server 地址和 Token,即可加入同一房间与真机设备互通。当成功开始音视频通话时,可以听到远端的音频,看到远端的视频画面。

5.6 停止推拉流

1. 停止推流/预览

调用 stopPublishingStream 接口停止发送本地的音视频流,结束通话。

/* 停止推流 /
ZegoExpressEngine.instance().stopPublishingStream();

如果启用了本地预览,开发者可以在停止推流后根据业务需要调用 stopPreview 接口停止预览。
/* 停止本地预览 /
ZegoExpressEngine.instance().stopPreview();

2. 停止拉流

调用 stopPlayingStream 接口,停止拉取远端的音视频流。

/* 停止拉流 /
ZegoExpressEngine.instance().stopPlayingStream("streamID");

  1. 退出房间
    调用 logoutRoom 接口退出房间,本端会收到 roomStateUpdate 回调通知调用结果,并停止其所有推拉流以及本地预览。
    /* 退出房间 /
    ZegoExpressEngine.instance().logoutRoom('room1');

5.7 销毁引擎
调用 destroyEngine 接口销毁引擎,用于释放 SDK 使用的资源。
/* 销毁引擎 /
ZegoExpressEngine.destroyEngine();

结语:

你已经完成了第一个uni-app RTC项目了,可以与小伙伴多端进行音视频通话测试。
即构助力企业一周快速搭建音视频通话、秀场直播、语聊房、K歌房等场景,提供多种解决方案,同时即构每月赠送10000分钟免费时长。

获取更多文档、Demo、技术帮助

获取本文的Demo、开发文档、技术支持,访问即构文档中心

继续阅读 »

“一套代码,多端运行”是很多开发团队的梦想。ZEGO SDK基于uni-app跨平台框架支持iOS、Android、Windows、macOS、HarmonyOS、Web、小程序并支持平台间互通,快速实现搭建多端音视频通话,大大降低开发和学习成本。

本文将引导快速创建和运行第一个uni-app RTC项目,适合想要快速完成多端共用音视频项目的开发者;

1 准备环境

在开始集成 ZEGO Express SDK 前,请确保开发环境满足以下要求:
HBuilderX 3.0.0 或以上版本。
准备 iOS / Android 设备,版本要求如下:
iOS 9.0 或以上版本且支持音视频的 iOS 设备。
Android 4.4 或以上版本且支持音视频的 Android 设备。
iOS / Android 设备已经连接到 Internet。

2 项目准备

2.1 创建项目

进入即构官网,在控制台创建项目,并申请有效的 AppID,这一步很关键,appid为应用的唯一标识,如身份证号,是应用的身份证明,用于明确你的项目及组织身份。zego提供的服务也是基于APP ID;

App ID的获取方式很简单,只需3~5分钟,在即构官网-我的项目-创建即可。创建的项目信息可用于SDK的集成和配置;

2.2 Token 鉴权

登录房间时必须 使用 Token 鉴权 ,可参考 Token 鉴权教程
为了方便开发阶段的调试,开发者可直接在 ZEGO 控制台获取临时 Token(有效期为 24 小时) 来使用,详情请参考 控制台(新版) - 项目管理 中的 “项目信息”。

3 集成

3.1 项目设置

开始集成前,可参考如下步骤设置你的项目;
如已有项目,本步骤可忽略。
如需新建项目,可按照以下步骤创建你的新项目:

1.启动 HBuilderX,选择“文件 > 新建 > 项目”菜单。

2.在出现的表单中,选择 “uni-app” 平台,并填写项目名称。

3.单击“创建”,即可创建项目。

3.2 导入 SDK

在 ZEGO 官网下载 SDK

1.下载 Express-Video SDK 到本地,解压缩 “zego-ZegoExpressUniAppSDK” 文件。

2.将解压缩后的文件夹直接复制到项目工程根目录下的 “nativeplugins” 文件夹,如果没有该目录,请手动创建。

3.3 在 uni-app 项目中导入插件

1.单击项目目录的 “manifest.json” 文件后,单击“App原生插件配置”中的“选择本地插件”或“选择云端插件”。

2.在弹出的选择框中,选择 “ZegoExpress 音视频 SDK” 后,单击“确认”,即添加成功。

3.4 自定义调试基座

3.4.1 制作自定义调试基座
1.选择“运行 > 运行到手机或模拟器 > 制作自定义调试基座”菜单。

2.在弹出的界面中,按照 uni-app 教程,填写相关信息,并单击“打包”进行云打包。

打包成功后,控制台会收到 uni-app 的相关提示。

3.4.2 切换运行基座为自定义调试基座
自定义调试基座选择“运行 > 运行到手机或模拟器 > 运行基座选择 > 自定义调试基座”菜单。

4 集成 JS 封装层

1.导入 JS 封装层。

在插件市场的 ZegoExpressEngine 音视频插件(JS) 界面单击右侧的“使用 HBuilderX导入插件”。

导入的 JS 封装层将存储在 “components” 目录中。

2.导入后可以在业务代码中引入 JS 封装层,并调用 Express 相关接口,示例如下:

import ZegoExpressEngine from '@/components/zego-ZegoExpressUniApp-JS/lib/ZegoExpressEngine';

5 实现流程

用户通过 ZEGO Express SDK 进行视频通话的基本流程为:
用户 A、B 加入房间,用户 B 预览并将音视频流推送到 ZEGO 云服务(推流),用户 A 收到用户 B 推送音视频流的通知之后,在通知中播放用户 B 的音视频流(拉流)。

整个音视频通话推拉流过程的 API 调用时序如下图:

5.1 创建引擎

1. 创建界面

在创建引擎之前,ZEGO 推荐开发者添加以下界面元素,方便实现基本的实时音视频功能。

本地预览窗口
远端视频窗口
结束按钮

2. 创建引擎

调用 createEngineWithProfile 接口,将申请到的 AppID 传入参数 “appID”,创建引擎单例对象。
如果需要注册回调方法,开发者可根据实际需要,实现 ZegoEventListener 中的某些方法,创建引擎后可通过调用 on 接口设置回调。
// 导入
import ZegoExpressEngine from '@/components/zego-ZegoExpressUniApp-JS/lib/ZegoExpressEngine';

// 采用通用场景
const profile = {
appID : xxx,
scenario : 0
};

ZegoExpressEngine.createEngineWithProfile(profile)

5.2 登录房间

1. 登录

你可以调用 loginRoom 接口登录房间。roomID 和 user 的参数由您本地生成,但是需要满足以下条件:

同一个 AppID 内,需保证 “roomID” 全局唯一。
同一个 AppID 内,需保证 “userID” 全局唯一,建议开发者将 “userID” 与自己业务的账号系统进行关联。

let roomConfig = {};
//token 由用户自己的服务端生成,为了更快跑通流程,也可以通过即构控制台获取临时的音视频 token
roomConfig.token = "xxxx";
// 只有传入 “isUserStatusNotify” 参数取值为 “true” 的 ZegoRoomConfig,才能收到 onRoomUserUpdate 回调。
roomConfig.isUserStatusNotify = true;
// 登录房间
// 开始登录房间
ZegoExpressEngine.instance().loginRoom('room1', {'userID': 'id1', 'userName': 'user1'}, roomConfig);

2. 监听登录房间后的事件回调

可根据实际应用需要,在登录房间后监听想要关注的事件通知,比如房间状态更新、用户状态更新、流状态更新等。

roomStateUpdate:房间状态更新回调,登录房间后,当房间连接状态发生变更(如出现房间断开,登录认证失败等情况),SDK 会通过该回调通知。
roomUserUpdate:用户状态更新回调,登录房间后,当房间内有用户新增或删除时,SDK 会通过该回调通知。
只有调用 loginRoom 接口登录房间时传入 ZegoRoomConfig 配置,且 “isUserStatusNotify”参数取值为 “true” 时,用户才能收到 roomUserUpdate 回调。
roomStreamUpdate:流状态更新回调,登录房间后,当房间内有用户新推送或删除音视频流时,SDK 会通过该回调通知。

// 以下为常用的房间相关回调

ZegoExpressEngine.instance().on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
// 房间状态更新回调,登录房间后,当房间连接状态发生变更(如出现房间断开,登录认证失败等情况),SDK会通过该回调通知
}); ;

ZegoExpressEngine.instance().on('roomUserUpdate', (roomID, updateType, userList) => {
// 用户状态更新,登录房间后,当房间内有用户新增或删除时,SDK会通过该回调通知
});

ZegoExpressEngine.instance().on('roomStreamUpdate', (roomID, updateType, streamList) => {
// 流状态更新,登录房间后,当房间内有用户新推送或删除音视频流时,SDK会通过该回调通知
});

5.3 推流

1. 开始推流

调用 startPublishingStream 接口,传入流 ID 参数 “streamID”,向远端用户发送本端的音视频流。

/* 开始推流 /
ZegoExpressEngine.instance().startPublishingStream("streamID");

2. 启动本地预览

如果希望看到本端画面,可使用 标签设置预览视图,并调用 startPreview 接口启动本地预览。

<template>
<zego-local-view style="height: 403.84rpx;flex: 1;"></zego-local-view>
</template>

js部分:
/* 开始预览 /
ZegoExpressEngine.instance().startPreview()

3. 监听推流后的事件回调

根据实际应用需要,在推流后监听想要关注的事件通知,比如推流状态更新等。
publisherStateUpdate:推流状态更新回调,调用推流接口成功后,当推流状态发生变更,如出现网络中断导致推流异常等情况,SDK 在重试推流的同时,会通过该回调通知。

ZegoExpressEngine.instance().on("publisherStateUpdate", (streamID, state, errorCode, extendedData) => {
// 调用推流接口成功后,当推流器状态发生变更,如出现网络中断导致推流异常等情况,SDK在重试推流的同时,会通过该回调通知
//....
});

5.4 拉流

1. 开始拉流

使用 标签设置远端视频流视图,调用 startPlayingStream 接口,根据传入的流 ID 参数 “streamID”,拉取远端推送的音视频流。
<template>
<zego-remote-view :streamID="playStreamID" style="height: 403.84rpx;flex: 1"></zego-remote-view>
</template>

js部分:
/* 开始拉流 /
this.playStreamID = "StreamID_1"
ZegoExpressEngine.instance().startPlayingStream(this.playStreamID)

  1. 监听拉流后的事件回调
    根据实际应用需要,在拉流后监听想要关注的事件通知,比如拉流状态更新等。
    playerStateUpdate:拉流状态更新回调,调用拉流接口成功后,当拉流状态发生变更,如出现网络中断导致推流异常等情况,SDK 在重试拉流的同时,会通过该回调通知。

ZegoExpressEngine.instance().on("playerStateUpdate", (streamID, state, errorCode, extendedData) => {
/* 调用拉流接口成功后,当拉流器状态发生变更,如出现网络中断导致推流异常等情况,SDK在重试拉流的同时,会通过该回调通知 /
//....
});

5.5 体验实时音视频功能

在真机中运行项目,运行成功后,可以看到本端视频画面。
为方便体验,ZEGO 提供了一个 Web 端调试示例,在该页面下,输入相同的 AppID、RoomID、Server 地址和 Token,即可加入同一房间与真机设备互通。当成功开始音视频通话时,可以听到远端的音频,看到远端的视频画面。

5.6 停止推拉流

1. 停止推流/预览

调用 stopPublishingStream 接口停止发送本地的音视频流,结束通话。

/* 停止推流 /
ZegoExpressEngine.instance().stopPublishingStream();

如果启用了本地预览,开发者可以在停止推流后根据业务需要调用 stopPreview 接口停止预览。
/* 停止本地预览 /
ZegoExpressEngine.instance().stopPreview();

2. 停止拉流

调用 stopPlayingStream 接口,停止拉取远端的音视频流。

/* 停止拉流 /
ZegoExpressEngine.instance().stopPlayingStream("streamID");

  1. 退出房间
    调用 logoutRoom 接口退出房间,本端会收到 roomStateUpdate 回调通知调用结果,并停止其所有推拉流以及本地预览。
    /* 退出房间 /
    ZegoExpressEngine.instance().logoutRoom('room1');

5.7 销毁引擎
调用 destroyEngine 接口销毁引擎,用于释放 SDK 使用的资源。
/* 销毁引擎 /
ZegoExpressEngine.destroyEngine();

结语:

你已经完成了第一个uni-app RTC项目了,可以与小伙伴多端进行音视频通话测试。
即构助力企业一周快速搭建音视频通话、秀场直播、语聊房、K歌房等场景,提供多种解决方案,同时即构每月赠送10000分钟免费时长。

获取更多文档、Demo、技术帮助

获取本文的Demo、开发文档、技术支持,访问即构文档中心

收起阅读 »

hbuilder 太耗内存了

内存 HBuilder

我目前hbuilder中只有一个项目,运行一段时间时间之后,太耗内存

我目前hbuilder中只有一个项目,运行一段时间时间之后,太耗内存

高效实现uni-app页面路由模块化及路径个性化

路由 路由守卫 路由拦截 动态路由 uniapp

高效实现uni-app页面路由模块化及路径个性化

在传统的uni-app开发中,我们被限制在手动维护pages.json文件中,以定义页面和页面样式特性。然而,随着应用程序复杂度的增加,这种方式会显著增加开发者的心智负担。面对庞大的项目和频繁的页面更新,pages.json的管理变得非常繁琐和不便。

然而,幸运的是,采用uni-simple-router后,这些问题迎刃而解。uni-simple-router为我们提供了一种更灵活、更高效的方式来处理页面路由。不再依赖于pages.json,我们可以动态地创建页面路由,甚至允许构建复杂的页面结构,如动态路由和嵌套路由等。

创建一个传统页面

传统方案

// pages.json  
{  
    "pages": [   
        {  
            "path": "pages/index/index"  
        }  
    ],  
  "globalStyle": {  
        "navigationBarTextStyle": "black",  
        "navigationBarTitleText": "uni-app",  
        "navigationBarBackgroundColor": "#F8F8F8",  
        "backgroundColor": "#F8F8F8"  
    }  
}

使用 uni-simple-router

// router.js  
const router = createRouter({  
  routes:[{  
      path:`/`,  
      component:__dynamicImportComponent__(`@/pages/index/index.vue`,{  
          pageType:`top`    
      })  
  }]  
})
// pages.json  
{  
  "globalStyle": {  
        "navigationBarTextStyle": "black",  
        "navigationBarTitleText": "uni-app",  
        "navigationBarBackgroundColor": "#F8F8F8",  
        "backgroundColor": "#F8F8F8"  
    }  
}

阅读须知:

为了减轻阅读复杂度,我们去除了一些非必要的代码,仅提供了绝对有用的部分。如果你想了解详细,可以参考从显示 Hello Word 开始

uni-simple-router中注册页面非常简单和方便。要注册一个页面,只需使用__dynamicImportComponent__辅助函数,并传入所需的组件即可。这样做会使页面组件根据不同平台进行编译,以适应各种环境。

此外,当注册顶级页面时,你还可以轻松配置uni-app的页面样式,支持所有uni-app页面样式的设置,详细你可以在这里查看到

为顶级页面设置样式

正如前文所述,当你在uni-simple-router中注册一个顶级页面时,该页面会继承uni-app的所有属性和事件。这使得在__dynamicImportComponent__函数中设置页面的样式和其他属性与在pages.json文件中设置样式效果一样,依然有效。

传统方案

// pages.json  
{  
"pages": [{  
    "path": "pages/index/index",  
    "style": {  
      "navigationBarTitleText":"uni-simple-router",   
      "navigationBarBackgroundColor":"#42b883",   
      "navigationBarTextStyle":"white"  
    }  
  }],  
  "globalStyle": {  
    "navigationBarTextStyle": "black",  
    "navigationBarTitleText": "uni-app",  
    "navigationBarBackgroundColor": "#F8F8F8",  
    "backgroundColor": "#F8F8F8"  
  }  
}

使用 uni-simple-router

// router.js  
const router = createRouter({  
  routes:[{  
      path:`/`,  
      component:__dynamicImportComponent__(`@/pages/index/index.vue`,{  
          pageType:`top`,  
          style:{   
              navigationBarTitleText:`uni-simple-router`,   
              navigationBarBackgroundColor:`#42b883`,   
              navigationBarTextStyle:`white`    
          }   
      })  
  }]  
})
// pages.json  
{  
  "globalStyle": {  
        "navigationBarTextStyle": "black",  
        "navigationBarTitleText": "uni-app",  
        "navigationBarBackgroundColor": "#F8F8F8",  
        "backgroundColor": "#F8F8F8"  
    }  
}

创建页面组件分包

除了能根据不同平台适配导入组件,__dynamicImportComponent__函数还允许你在该函数中设置组件分包。

假设你现在有如下两个页面配置:

// router.js  
const router = createRouter({  
  routes:[{  
      path:`/`,  
      component:__dynamicImportComponent__(`@/pages/index/index.vue`,{  
        pageType:`top`,  
        package: {    
          type: `child`  
        },   
      })  
  },{  
      path:`/pkg1`,  
      component:__dynamicImportComponent__(`@/pkg/pkg1/index.vue`,{  
        pageType:`top`,  
        package: {    
          type: `child`,  
          name: `pkg/pkg1`  
        },   
      })  
  }]  
})

相当于在 pages.json 文件中配置 subPackages 字段一样:

{  
  "subPackages": [  
    {  
      "root": "pkg/pkg1",  
      "pages": [{  
        "path": "index",  
      }]  
    },   
    {  
      "root": "pages",  
      "pages": [{  
        "path": "index/index",  
      }]  
    }  
  ],  
}

如需了解详细,请查看 将导入的组件分包

创建嵌套页面结构

uni-app开发中,对于嵌套页面的需求非常普遍,然而,官方并没有提供内建的嵌套路由解决方案,这导致开发者不得不寻找其他替代方案。在截至uni-simple-router v3版本发布之前,跨端嵌套解决方案相对较难实现。

由于官方未提供直接支持,开发者在嵌套页面的实现上面临一些挑战。不过,uni-simple-router v3版本的推出为开发者带来了更为便捷和灵活的解决方案,使嵌套页面的使用变得更加简单和高效。

通过使用uni-simple-router v3版本,开发者现在可以更方便地实现嵌套页面,无论是在同一端还是跨多端的情况下,都能得到很好的支持。这为uni-app开发带来了更多可能性和创意的空间,使开发过程变得更加顺畅和愉快。

// router.js  
const router = createRouter({  
  routes:[{  
    path: '/admin',  
    component: __dynamicImportComponent__(`@/pages/AdminLayout.vue`,{  
      pageType:`top`,  
    }),  
    children: [  
      {  
        path: 'dashboard',  
        component: __dynamicImportComponent__(`@/pages/DashboardPage.vue`)  
      },  
      {  
        path: 'users',  
        component: __dynamicImportComponent__(`@/pages/UsersPage.vue`)  
      },  
      {  
        path: 'settings',  
        component: __dynamicImportComponent__(`@/pages/SettingsPage.vue`)  
      }  
    ]  
  }];  
})
<!-- AdminLayout.vue -->  
<template>  
  <div>  
    <sidebar></sidebar>  
    <main>  
      <simple-router-view></simple-router-view>  
    </main>  
  </div>  
</template>

通过使用嵌套路由,你可以构建出更复杂的页面布局和导航结构,将不同功能模块拆分成独立的路由组件,并嵌套在父级路由中,实现更灵活和可扩展的应用程序架构,详细请查看 嵌套路由

自定义路径匹配

uni-simple-router中,当你不再使用pages.json来定义页面时,你可以轻松地自定义path,而不再担心路径无法自定义的问题。

通过使用__dynamicImportComponent__函数来导入组件,并在路由配置中进行自定义path的设置,你完全可以根据自己的需求来定义页面的路径。这种灵活性让你能够更加自由地组织和管理页面结构,而无需受限于pages.json的固定配置。

伪静态格式

  • router.js
    const router = createRouter({  
    platform: process.env.VUE_APP_PLATFORM,  
    routes:[{  
        path:`/class/:id(\\d+).html`,  
        component: Home  
    }]  
    })
  • URL表现
    http://localhost:5174/#/class/6.html

静态路径格式

  • router.js
    const router = createRouter({  
    platform: process.env.VUE_APP_PLATFORM,  
    routes:[{  
        path:`/home`,  
        component: Home  
    }]  
    })
  • URL表现
    http://localhost:5174/#/home

复杂分类

  • router.js
    const router = createRouter({  
    platform: process.env.VUE_APP_PLATFORM,  
    routes:[{  
        path:`/product/:category(\\w+)/:subCategory(\\w+)`,  
        component: Product  
    }]  
    })
  • URL表现
    http://localhost:5174/#/product/electronics/phones

指定字符

  • router.js
    const router = createRouter({  
    platform: process.env.VUE_APP_PLATFORM,  
    routes:[{  
        path:`/category/:name(\\w+)`,  
        component: Category  
    }]  
    })
  • URL表现
    http://localhost:5174/#/category/books

如果了解更多你可以查阅 路由匹配

继续阅读 »

高效实现uni-app页面路由模块化及路径个性化

在传统的uni-app开发中,我们被限制在手动维护pages.json文件中,以定义页面和页面样式特性。然而,随着应用程序复杂度的增加,这种方式会显著增加开发者的心智负担。面对庞大的项目和频繁的页面更新,pages.json的管理变得非常繁琐和不便。

然而,幸运的是,采用uni-simple-router后,这些问题迎刃而解。uni-simple-router为我们提供了一种更灵活、更高效的方式来处理页面路由。不再依赖于pages.json,我们可以动态地创建页面路由,甚至允许构建复杂的页面结构,如动态路由和嵌套路由等。

创建一个传统页面

传统方案

// pages.json  
{  
    "pages": [   
        {  
            "path": "pages/index/index"  
        }  
    ],  
  "globalStyle": {  
        "navigationBarTextStyle": "black",  
        "navigationBarTitleText": "uni-app",  
        "navigationBarBackgroundColor": "#F8F8F8",  
        "backgroundColor": "#F8F8F8"  
    }  
}

使用 uni-simple-router

// router.js  
const router = createRouter({  
  routes:[{  
      path:`/`,  
      component:__dynamicImportComponent__(`@/pages/index/index.vue`,{  
          pageType:`top`    
      })  
  }]  
})
// pages.json  
{  
  "globalStyle": {  
        "navigationBarTextStyle": "black",  
        "navigationBarTitleText": "uni-app",  
        "navigationBarBackgroundColor": "#F8F8F8",  
        "backgroundColor": "#F8F8F8"  
    }  
}

阅读须知:

为了减轻阅读复杂度,我们去除了一些非必要的代码,仅提供了绝对有用的部分。如果你想了解详细,可以参考从显示 Hello Word 开始

uni-simple-router中注册页面非常简单和方便。要注册一个页面,只需使用__dynamicImportComponent__辅助函数,并传入所需的组件即可。这样做会使页面组件根据不同平台进行编译,以适应各种环境。

此外,当注册顶级页面时,你还可以轻松配置uni-app的页面样式,支持所有uni-app页面样式的设置,详细你可以在这里查看到

为顶级页面设置样式

正如前文所述,当你在uni-simple-router中注册一个顶级页面时,该页面会继承uni-app的所有属性和事件。这使得在__dynamicImportComponent__函数中设置页面的样式和其他属性与在pages.json文件中设置样式效果一样,依然有效。

传统方案

// pages.json  
{  
"pages": [{  
    "path": "pages/index/index",  
    "style": {  
      "navigationBarTitleText":"uni-simple-router",   
      "navigationBarBackgroundColor":"#42b883",   
      "navigationBarTextStyle":"white"  
    }  
  }],  
  "globalStyle": {  
    "navigationBarTextStyle": "black",  
    "navigationBarTitleText": "uni-app",  
    "navigationBarBackgroundColor": "#F8F8F8",  
    "backgroundColor": "#F8F8F8"  
  }  
}

使用 uni-simple-router

// router.js  
const router = createRouter({  
  routes:[{  
      path:`/`,  
      component:__dynamicImportComponent__(`@/pages/index/index.vue`,{  
          pageType:`top`,  
          style:{   
              navigationBarTitleText:`uni-simple-router`,   
              navigationBarBackgroundColor:`#42b883`,   
              navigationBarTextStyle:`white`    
          }   
      })  
  }]  
})
// pages.json  
{  
  "globalStyle": {  
        "navigationBarTextStyle": "black",  
        "navigationBarTitleText": "uni-app",  
        "navigationBarBackgroundColor": "#F8F8F8",  
        "backgroundColor": "#F8F8F8"  
    }  
}

创建页面组件分包

除了能根据不同平台适配导入组件,__dynamicImportComponent__函数还允许你在该函数中设置组件分包。

假设你现在有如下两个页面配置:

// router.js  
const router = createRouter({  
  routes:[{  
      path:`/`,  
      component:__dynamicImportComponent__(`@/pages/index/index.vue`,{  
        pageType:`top`,  
        package: {    
          type: `child`  
        },   
      })  
  },{  
      path:`/pkg1`,  
      component:__dynamicImportComponent__(`@/pkg/pkg1/index.vue`,{  
        pageType:`top`,  
        package: {    
          type: `child`,  
          name: `pkg/pkg1`  
        },   
      })  
  }]  
})

相当于在 pages.json 文件中配置 subPackages 字段一样:

{  
  "subPackages": [  
    {  
      "root": "pkg/pkg1",  
      "pages": [{  
        "path": "index",  
      }]  
    },   
    {  
      "root": "pages",  
      "pages": [{  
        "path": "index/index",  
      }]  
    }  
  ],  
}

如需了解详细,请查看 将导入的组件分包

创建嵌套页面结构

uni-app开发中,对于嵌套页面的需求非常普遍,然而,官方并没有提供内建的嵌套路由解决方案,这导致开发者不得不寻找其他替代方案。在截至uni-simple-router v3版本发布之前,跨端嵌套解决方案相对较难实现。

由于官方未提供直接支持,开发者在嵌套页面的实现上面临一些挑战。不过,uni-simple-router v3版本的推出为开发者带来了更为便捷和灵活的解决方案,使嵌套页面的使用变得更加简单和高效。

通过使用uni-simple-router v3版本,开发者现在可以更方便地实现嵌套页面,无论是在同一端还是跨多端的情况下,都能得到很好的支持。这为uni-app开发带来了更多可能性和创意的空间,使开发过程变得更加顺畅和愉快。

// router.js  
const router = createRouter({  
  routes:[{  
    path: '/admin',  
    component: __dynamicImportComponent__(`@/pages/AdminLayout.vue`,{  
      pageType:`top`,  
    }),  
    children: [  
      {  
        path: 'dashboard',  
        component: __dynamicImportComponent__(`@/pages/DashboardPage.vue`)  
      },  
      {  
        path: 'users',  
        component: __dynamicImportComponent__(`@/pages/UsersPage.vue`)  
      },  
      {  
        path: 'settings',  
        component: __dynamicImportComponent__(`@/pages/SettingsPage.vue`)  
      }  
    ]  
  }];  
})
<!-- AdminLayout.vue -->  
<template>  
  <div>  
    <sidebar></sidebar>  
    <main>  
      <simple-router-view></simple-router-view>  
    </main>  
  </div>  
</template>

通过使用嵌套路由,你可以构建出更复杂的页面布局和导航结构,将不同功能模块拆分成独立的路由组件,并嵌套在父级路由中,实现更灵活和可扩展的应用程序架构,详细请查看 嵌套路由

自定义路径匹配

uni-simple-router中,当你不再使用pages.json来定义页面时,你可以轻松地自定义path,而不再担心路径无法自定义的问题。

通过使用__dynamicImportComponent__函数来导入组件,并在路由配置中进行自定义path的设置,你完全可以根据自己的需求来定义页面的路径。这种灵活性让你能够更加自由地组织和管理页面结构,而无需受限于pages.json的固定配置。

伪静态格式

  • router.js
    const router = createRouter({  
    platform: process.env.VUE_APP_PLATFORM,  
    routes:[{  
        path:`/class/:id(\\d+).html`,  
        component: Home  
    }]  
    })
  • URL表现
    http://localhost:5174/#/class/6.html

静态路径格式

  • router.js
    const router = createRouter({  
    platform: process.env.VUE_APP_PLATFORM,  
    routes:[{  
        path:`/home`,  
        component: Home  
    }]  
    })
  • URL表现
    http://localhost:5174/#/home

复杂分类

  • router.js
    const router = createRouter({  
    platform: process.env.VUE_APP_PLATFORM,  
    routes:[{  
        path:`/product/:category(\\w+)/:subCategory(\\w+)`,  
        component: Product  
    }]  
    })
  • URL表现
    http://localhost:5174/#/product/electronics/phones

指定字符

  • router.js
    const router = createRouter({  
    platform: process.env.VUE_APP_PLATFORM,  
    routes:[{  
        path:`/category/:name(\\w+)`,  
        component: Category  
    }]  
    })
  • URL表现
    http://localhost:5174/#/category/books

如果了解更多你可以查阅 路由匹配

收起阅读 »

G-Media 2023 | 每日互动使用大模型实现“智选人群”

如今“百模大战”,每日互动在持续打磨数据营销服务能力的同时,密切关注行业趋势,积极探索AIGC、大模型等前沿技术在品牌营销等垂直领域的应用。7月19日,G-Media 2023正式开幕。现场,每日互动(个推)创始人、CEO方毅以“Grow with Evolution:要变,还得是绝活儿”为主题发表了精彩演讲,结合当下技术和行业热点,方毅分享了每日互动在大模型应用方面的探索。

方毅认为,对于品牌营销等垂直行业来讲,要真正发挥出大模型的巨大能力,还需要把模型用“活”,即结合“行业知识”对大模型进行特定的训练,让大模型听得懂“行话”。只有这样,一线的营销从业人员才能自如、灵活地使用日常惯用的“行话”向大模型提问,大模型也才能发挥出自己的实力,帮助解决具体业务场景中的问题。

在G-Media 2021,每日互动方毅曾分享过独创的“数据营销五步法”。“五步法”沉淀了每日互动的数据建模经验,其核心是将品牌一方数据作为“Y值”,让AI模型去分析和学习种子人群的线上线下偏好特征,形成智能预测能力,然后去做相似性扩量,找到更多的目标TA。

但是对于无法提供“Y值”的品牌,该如何进行相似性扩量呢?懂“行话”的大模型就能很好地解决这一问题。每日互动把自身在品牌营销领域沉淀的丰富经验、Know-how,打造形成行业知识库,“喂”给大模型学习,让大模型能够听得懂行话并使用行话输出它对品牌、消费人群的人文特征理解;同时使用编织技术,实现行业知识库和每日互动大数据标签特征库的打通,让大模型能够结合每日互动的数据能力,帮助品牌客户洞察细分人群的数据特征,并在每日互动的全网流量池中进行相似性扩量。

方毅介绍,每日互动正在打造的“智选人群”功能,就是这样的实现原理。营销人员可以像日常对话一样,向大模型提问,比如“新能源车主人群有哪些特征”。经过每日互动行业知识库和历史经验精调后的大模型,不仅能够理解用户的语言,还能快速输出匹配的洞察结果和人群方案,更精准地在每日互动流量池中进行相似人群的扩量。品牌直接调用每日互动的“智选人群”功能,就可以快速地对细分人群进行画像洞察,并加速实现相似性扩量,智能定向高潜TA,提升TA浓度,将“对话式生成”的目标人群一键对接多种媒体平台,高效完成广告投放,大幅提升营销效能。

方毅表示,正如今年G-Media峰会的主题——“信任与信心”,每日互动将不断升级数据营销服务能力,同时也将以互信为前提,和各行业伙伴携手,共同建设一个安全、高效、透明的品牌数字化营销新生态,提振行业各方对于可持续增长的信心。

继续阅读 »

如今“百模大战”,每日互动在持续打磨数据营销服务能力的同时,密切关注行业趋势,积极探索AIGC、大模型等前沿技术在品牌营销等垂直领域的应用。7月19日,G-Media 2023正式开幕。现场,每日互动(个推)创始人、CEO方毅以“Grow with Evolution:要变,还得是绝活儿”为主题发表了精彩演讲,结合当下技术和行业热点,方毅分享了每日互动在大模型应用方面的探索。

方毅认为,对于品牌营销等垂直行业来讲,要真正发挥出大模型的巨大能力,还需要把模型用“活”,即结合“行业知识”对大模型进行特定的训练,让大模型听得懂“行话”。只有这样,一线的营销从业人员才能自如、灵活地使用日常惯用的“行话”向大模型提问,大模型也才能发挥出自己的实力,帮助解决具体业务场景中的问题。

在G-Media 2021,每日互动方毅曾分享过独创的“数据营销五步法”。“五步法”沉淀了每日互动的数据建模经验,其核心是将品牌一方数据作为“Y值”,让AI模型去分析和学习种子人群的线上线下偏好特征,形成智能预测能力,然后去做相似性扩量,找到更多的目标TA。

但是对于无法提供“Y值”的品牌,该如何进行相似性扩量呢?懂“行话”的大模型就能很好地解决这一问题。每日互动把自身在品牌营销领域沉淀的丰富经验、Know-how,打造形成行业知识库,“喂”给大模型学习,让大模型能够听得懂行话并使用行话输出它对品牌、消费人群的人文特征理解;同时使用编织技术,实现行业知识库和每日互动大数据标签特征库的打通,让大模型能够结合每日互动的数据能力,帮助品牌客户洞察细分人群的数据特征,并在每日互动的全网流量池中进行相似性扩量。

方毅介绍,每日互动正在打造的“智选人群”功能,就是这样的实现原理。营销人员可以像日常对话一样,向大模型提问,比如“新能源车主人群有哪些特征”。经过每日互动行业知识库和历史经验精调后的大模型,不仅能够理解用户的语言,还能快速输出匹配的洞察结果和人群方案,更精准地在每日互动流量池中进行相似人群的扩量。品牌直接调用每日互动的“智选人群”功能,就可以快速地对细分人群进行画像洞察,并加速实现相似性扩量,智能定向高潜TA,提升TA浓度,将“对话式生成”的目标人群一键对接多种媒体平台,高效完成广告投放,大幅提升营销效能。

方毅表示,正如今年G-Media峰会的主题——“信任与信心”,每日互动将不断升级数据营销服务能力,同时也将以互信为前提,和各行业伙伴携手,共同建设一个安全、高效、透明的品牌数字化营销新生态,提振行业各方对于可持续增长的信心。

收起阅读 »

Android应用签名MD5格式不正确,请填写MD5格式的签名

一键登录

申请一键登录时,添加应用,提示“Android应用签名MD5格式不正确,请填写MD5格式的签名”。
原因是jdk的版本不同生成的值不同,可以使用java1.8.0_201版本,亲测可以。
点击下面的链接,找到201版本的jdk版本下载就好了。
java1.8.0_201

继续阅读 »

申请一键登录时,添加应用,提示“Android应用签名MD5格式不正确,请填写MD5格式的签名”。
原因是jdk的版本不同生成的值不同,可以使用java1.8.0_201版本,亲测可以。
点击下面的链接,找到201版本的jdk版本下载就好了。
java1.8.0_201

收起阅读 »

IOS 监听APP退出

监听 iOS

let NSNotificationCenterClass = plus.ios.importClass("NSNotificationCenter");
let NSNotificationCenterObj = NSNotificationCenterClass.defaultCenter();
let num = 0 ;
plus.ios.invoke(NSNotificationCenterObj, "addObserverForName:object:queue:usingBlock:",
"UIApplicationWillTerminateNotification", null, null, function() {
// UIApplicationWillTerminateNotification 是应用即将终止的时候调用,但是我发现并没有调用 ,
// 得出最终结论 :
// 1.应用在前台,双击 Home 键 ,终止应用 , UIApplicationWillTerminateNotification 调用
// 2.应用在前台,单击 Home 键,进入桌面 , 再终止应用 UIApplicationWillTerminateNotification 不会被调用.
//应用在前台,双击Home键,杀掉调用 ,但是应用在后台,双击Home键, 再终止应用不会被通知
});
plus.ios.invoke(NSNotificationCenterObj, "addObserverForName:object:queue:usingBlock:",
"UIApplicationDidBecomeActiveNotification", null, null, function(){
num = 0;
console.log('启动');
});
plus.ios.invoke(NSNotificationCenterObj, "addObserverForName:object:queue:usingBlock:",
"UIApplicationDidEnterBackgroundNotification", null, null, function(){
num++
if(num ==2){
//杀死APP进程关闭直播
uni.$TrtcCloud.exitRoom();
}
console.log(num)
});
觉得用uni-app onHide生命周期也可以实现 ,因为无论是退出APP还是隐藏在后台onHide都会被执行,那么做个定时任务通知服务端APP退出了。
或者说做个debounce在连续的操作中,无论进行了多长时间,只有某一次的操作后在指定的时间内没有再操作,这一次才被判定有效 。

继续阅读 »

let NSNotificationCenterClass = plus.ios.importClass("NSNotificationCenter");
let NSNotificationCenterObj = NSNotificationCenterClass.defaultCenter();
let num = 0 ;
plus.ios.invoke(NSNotificationCenterObj, "addObserverForName:object:queue:usingBlock:",
"UIApplicationWillTerminateNotification", null, null, function() {
// UIApplicationWillTerminateNotification 是应用即将终止的时候调用,但是我发现并没有调用 ,
// 得出最终结论 :
// 1.应用在前台,双击 Home 键 ,终止应用 , UIApplicationWillTerminateNotification 调用
// 2.应用在前台,单击 Home 键,进入桌面 , 再终止应用 UIApplicationWillTerminateNotification 不会被调用.
//应用在前台,双击Home键,杀掉调用 ,但是应用在后台,双击Home键, 再终止应用不会被通知
});
plus.ios.invoke(NSNotificationCenterObj, "addObserverForName:object:queue:usingBlock:",
"UIApplicationDidBecomeActiveNotification", null, null, function(){
num = 0;
console.log('启动');
});
plus.ios.invoke(NSNotificationCenterObj, "addObserverForName:object:queue:usingBlock:",
"UIApplicationDidEnterBackgroundNotification", null, null, function(){
num++
if(num ==2){
//杀死APP进程关闭直播
uni.$TrtcCloud.exitRoom();
}
console.log(num)
});
觉得用uni-app onHide生命周期也可以实现 ,因为无论是退出APP还是隐藏在后台onHide都会被执行,那么做个定时任务通知服务端APP退出了。
或者说做个debounce在连续的操作中,无论进行了多长时间,只有某一次的操作后在指定的时间内没有再操作,这一次才被判定有效 。

收起阅读 »

全栈经验,有项目可以联系我

唐山市极信网络科技有限公司是一家专注于各行业小程序、APP、商城、平台电商/直播电商/跨境电商,erp、crm类管理系统、智慧园区、智慧校园、智慧社区、数字孪生、数字大屏 的科技公司。公司以“极致服务、诚信经营”为宗旨,致力于为客户提供最优质的解决方案。公司拥有一支年轻而又专业的团队,拥有丰富的行业经验。
有需要联系我!!!
V:15033452950

继续阅读 »

唐山市极信网络科技有限公司是一家专注于各行业小程序、APP、商城、平台电商/直播电商/跨境电商,erp、crm类管理系统、智慧园区、智慧校园、智慧社区、数字孪生、数字大屏 的科技公司。公司以“极致服务、诚信经营”为宗旨,致力于为客户提供最优质的解决方案。公司拥有一支年轻而又专业的团队,拥有丰富的行业经验。
有需要联系我!!!
V:15033452950

收起阅读 »

HBuilderX 越更新BUG越多,越来越卡!!

HBuilderX

HBuilderX 越更新BUG越多,越来越卡!!

HBuilderX 越更新BUG越多,越来越卡!!

兼职接单,多年uniapp开发经验

如题,有单的老板,请砸

如题,有单的老板,请砸

mui时间选择器在iOS16.4上出现偏移不正常的bug

mui picker

这里要清楚是样式导致的问题
可以看看如下链接怎么处理的:https://blog.csdn.net/feeeee889/article/details/131490861

或是以下步骤:
mui.picker.all.js中添加
if (isIos) {
//-----------------添加部分
if (mui.os.ios && mui.os.plus && plus.os.version >= "16.2") {
return;
}
var maches = userAgent.match(/iphone os ([\d_]+) /i);
if (maches && maches.length >= 2 && maches[1] >= "16_2"){
return;
}
//-----------------添加部分
self.list.style.webkitTransformOrigin = "center center " + self.r + "px";

}
mui.picker.css中注释
.mui-picker-inner {
/ 16.4及以上注释 /
/ -webkit-mask-box-image: -webkit-linear-gradient(bottom, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent);
-webkit-mask-box-image: linear-gradient(top, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent) /
}
亲测有效!!!

继续阅读 »

这里要清楚是样式导致的问题
可以看看如下链接怎么处理的:https://blog.csdn.net/feeeee889/article/details/131490861

或是以下步骤:
mui.picker.all.js中添加
if (isIos) {
//-----------------添加部分
if (mui.os.ios && mui.os.plus && plus.os.version >= "16.2") {
return;
}
var maches = userAgent.match(/iphone os ([\d_]+) /i);
if (maches && maches.length >= 2 && maches[1] >= "16_2"){
return;
}
//-----------------添加部分
self.list.style.webkitTransformOrigin = "center center " + self.r + "px";

}
mui.picker.css中注释
.mui-picker-inner {
/ 16.4及以上注释 /
/ -webkit-mask-box-image: -webkit-linear-gradient(bottom, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent);
-webkit-mask-box-image: linear-gradient(top, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent) /
}
亲测有效!!!

收起阅读 »

HBuilderX 内存占用过高导致系统崩溃

HBuilderX 进程已崩溃

HBuilderX 内存占用过高导致系统崩溃,2021 Mac book pro 14寸

HBuilderX 内存占用过高导致系统崩溃,2021 Mac book pro 14寸

支付宝支付一直报错:商家订单参数异常

支付宝支付

在接收到后台传递过来的订单信息后,在自己拼接后发现自己的格式上是没问题的,参数应该也是没问题的,但是一直报错说商家订单参数异常。
后来我在支付宝的社区里面看到官方提供的一个CSDN老哥免费分享的支付宝支付测试用apk,安装后发现,不是我这边的uni-app问题,后端老哥经过排查后发现,原来是sign在网页和APP需要不同方法生成。
最难顶的部分来了,不知道为什么,前端这边拼接的orderInfo就是不行,明明看起来格式也没毛病,然后后端也返回一个拼接的字符串,就是可以。
难道 js 和 Java的转义哪些不一样?

继续阅读 »

在接收到后台传递过来的订单信息后,在自己拼接后发现自己的格式上是没问题的,参数应该也是没问题的,但是一直报错说商家订单参数异常。
后来我在支付宝的社区里面看到官方提供的一个CSDN老哥免费分享的支付宝支付测试用apk,安装后发现,不是我这边的uni-app问题,后端老哥经过排查后发现,原来是sign在网页和APP需要不同方法生成。
最难顶的部分来了,不知道为什么,前端这边拼接的orderInfo就是不行,明明看起来格式也没毛病,然后后端也返回一个拼接的字符串,就是可以。
难道 js 和 Java的转义哪些不一样?

收起阅读 »