uni-app 开发微信小程序实践案例:对接 uView、地图定位与微信能力
uni-app 开发微信小程序实践案例:对接 uView、地图定位与微信能力
本文以一个「门店/活动类」小程序常见需求为例,说明如何用 uni-app 编译到 微信小程序,UI 统一对接 uView UI,并集成 微信地图与定位、获取手机号 等能力,同时对比 微信原生框架 的取舍与 uni-app 注意点。
1. UI 方案:uView 与 uni-app 版本对应
本案例的 UI 层以 uView 为准(通过 uni_modules 安装,组件前缀多为 u-)。
| 套件 | 适用工程 | 说明 |
|---|---|---|
| uView UI 2.x | uni-app + Vue 2 | 生态成熟,文档与示例多 |
| uView Plus | uni-app + Vue 3 | Vue 3 项目选这一套,勿与 2.x 混装 |
安装与引入步骤以 uView 官方文档(或 uView Plus 站点)为准:一般包括 uni_modules 安装、在 main.js / main.ts 中 app.use(uView)、在 uni.scss 引入主题变量、在 pages.json 配置 easycom 实现 u- 组件按需加载。
名称辨析(避免搜错文档):口语里的「iView」多指 Web 后台的 View UI,与 uView 不是同一套库;小程序里对接 uni-app 组件库 请直接搜 uView / uView Plus。
2. 案例背景(可落地的需求切片)
场景:线下活动报名页——需要展示地图选点、用户当前位置、表单里一键授权手机号(后端落库)。
技术栈:uni-app → 发行 mp-weixin;界面用 uView(如 u-button、u-cell、u-form、u-modal 等);地图仍用原生 <map>(与 uView 不冲突);定位用 uni.getLocation;手机号用 u-button 的 open-type="getPhoneNumber"(需组件透传)或原生 button + 样式类同 uView。
3. 与「微信原生框架」对比:优点与代价
3.1 uni-app + uView 相对原生的优点
- 一套代码多端:同一业务可编译到微信、支付宝、H5、App 等(各端用条件编译处理差异)。
- Vue + uView 组件化:表单、列表、反馈类页面开发效率高,视觉与交互有统一规范。
- 工程化:npm、TypeScript、ESLint 等与前端工程对齐(视脚手架与版本而定)。
3.2 相对原生的不足或成本
- 调试链路更长:问题可能出在 Vue、编译器或微信基础库,排查比纯原生多一层。
- 包体积:uView 需 easycom 按需;避免全量引入导致主包过大。
- 新特性滞后:微信新 API 可能需
#ifdef MP-WEIXIN直接调原生。 - 极致性能场景:复杂 canvas、游戏级动画等,原生或更可控。
简要结论:业务型、以表单/列表/地图为主的小程序,uni-app + uView 性价比高;强依赖最新微信底层能力或体积极致敏感时,要评估是否原生或混合。
4. 对接 uView:安装与使用要点
4.1 推荐步骤(概念清单)
- 用 HBuilderX 或 CLI 创建 uni-app 工程,先定 Vue2 或 Vue3,再选 uView 2.x 或 uView Plus。
- 通过 uni_modules 安装对应 uView 包。
- 按官方文档完成 main 入口、uni.scss 变量、pages.json → easycom。
- 页面中直接使用
<u-button>、<u-input>等;无需每个页面手动 import(easycom 生效时)。
4.2 使用注意
- 按需加载:配置
easycom规则,只打包实际用到的u-组件。 - 微信开放能力按钮:
open-type(如getPhoneNumber、chooseAvatar)务必确认当前 uView 版本 是否将属性透传到原生 button。若文档未保证,手机号按钮建议用原生<button>+ 自定义 class,避免授权失败。 - 主题:通过
uni.scss覆盖 uView 变量,保持与品牌色一致。
4.3 代码佐证:入口、uni.scss 与 easycom(Vue2 + uView 2.x)
下面与 uView 官方文档一致,仅作结构佐证;Vue3 请改用 uView Plus 的安装方式。
main.js 中全局注册:
import Vue from "vue";
import App from "./App";
import uView from "uview-ui";
Vue.use(uView);
const app = new Vue({ ...App });
app.$mount();
uni.scss 引入主题变量(路径以你实际安装位置为准,uni_modules 方式可能不同):
@import "uview-ui/theme.scss";
pages.json 中配置 easycom,使 u-button 等无需逐页 import(规则以 uView 文档为准):
{
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
}
}
}
5. 微信地图、定位:uni-app 写法与注意点
5.1 能力说明
- 地图展示:使用
<map>(编译到微信小程序为原生 map);外围可用 uView 的u-card、u-gap等排版。 - 获取经纬度:
uni.getLocation(对应wx.getLocation)。 - 选点:
uni.chooseLocation(需权限与隐私说明)。
5.2 权限与隐私合规(必做)
- 在微信小程序后台配置「用户隐私保护指引」。
- 在
manifest.json→ 微信小程序 中配置scope.userLocation说明。 - 敏感接口按当前微信要求配置(如
requiredPrivateInfos,以微信与 uni-app 最新文档为准)。
5.3 坐标系
- 一般使用
gcj02;与高德/百度等混用时注意坐标转换。
5.4 代码佐证:<map> 与 uni.getLocation
模板里使用原生 <map>(编译到微信小程序即原生 map),与 uView 的 u-gap、u-button 可同页混用:
<map
class="map"
:latitude="lat"
:longitude="lng"
:markers="markers"
show-location
@markertap="onMarkerTap"
/>
定位统一走 uni.getLocation,类型选 gcj02 与微信地图一致;成功后更新 lat/lng 与 markers:
uni.getLocation({
type: "gcj02",
isHighAccuracy: true,
success: (res) => {
this.lat = res.latitude;
this.lng = res.longitude;
this.markers = [
{
id: 1,
latitude: res.latitude,
longitude: res.longitude,
title: "当前位置",
width: 30,
height: 30,
},
];
},
fail: (err) => {
uni.showToast({ title: "请开启定位权限", icon: "none" });
},
});
可选:在业务里调用 uni.chooseLocation 让用户选点,返回的名称、地址、经纬度同样可用于更新 markers。
5.5 代码佐证:权限与隐私(manifest / pages.json)
微信小程序需在 manifest.json → mp-weixin 中声明位置用途;敏感能力字段名随微信版本调整,以当时文档为准。示意:
{
"mp-weixin": {
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序地图展示"
}
},
"requiredPrivateInfos": ["getLocation"]
}
}
亦可在 pages.json 的 mp-weixin 节点补充 permission(与工程习惯二选一或并存,以 uni-app 编译结果为准)。例如与 easycom、页面路由写在同一份 pages.json 时,可合并为:
{
"pages": [
{
"path": "pages/demo/index",
"style": { "navigationBarTitleText": "地图与授权示例" }
}
],
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
}
},
"mp-weixin": {
"requiredPrivateInfos": ["getLocation"],
"permission": {
"scope.userLocation": {
"desc": "用于在地图上展示你的位置"
}
}
}
}
5.6 完整单页示例(uView + 地图 + 定位 + 手机号)
以下为一页 pages/demo/index.vue 的节选,可直接拷贝到工程(需已安装 uView 并配置 easycom;https://你的域名 换成合法业务域名):
<template>
<view class="page">
<u-gap height="20" />
<map
class="map"
:latitude="lat"
:longitude="lng"
:markers="markers"
show-location
@markertap="onMarkerTap"
/>
<u-gap height="24" />
<u-button type="primary" @click="getLocation"
>获取定位(uni.getLocation)</u-button
>
<u-gap height="24" />
<u-button open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
授权手机号
</u-button>
<u-gap height="16" />
<u-text
type="info"
size="12"
text="手机号 code 请发到自有后端解密,勿在前端拼 session_key。"
/>
</view>
</template>
<script>
export default {
data() {
return {
lat: 39.908823,
lng: 116.39747,
markers: [
{
id: 1,
latitude: 39.908823,
longitude: 116.39747,
title: "示例点",
width: 30,
height: 30,
},
],
};
},
methods: {
getLocation() {
uni.getLocation({
type: "gcj02",
isHighAccuracy: true,
success: (res) => {
this.lat = res.latitude;
this.lng = res.longitude;
this.markers = [
{
id: 1,
latitude: res.latitude,
longitude: res.longitude,
title: "当前位置",
width: 30,
height: 30,
},
];
},
fail: () => {
uni.showToast({ title: "请开启定位权限", icon: "none" });
},
});
},
onMarkerTap(e) {
console.log("marker", e.detail);
},
onGetPhoneNumber(e) {
// #ifdef MP-WEIXIN
if (e.detail.errMsg === "getPhoneNumber:ok") {
const code = e.detail.code;
uni.request({
url: "https://你的域名/api/wx/phone",
method: "POST",
data: { code },
});
} else {
uni.showToast({ title: "用户未授权", icon: "none" });
}
// #endif
},
},
};
</script>
<style scoped>
.page {
padding: 24rpx;
}
.map {
width: 100%;
height: 420rpx;
border-radius: 12rpx;
overflow: hidden;
}
</style>
6. 获取微信用户信息与手机号
6.1 用户信息(头像、昵称)
政策与接口常更新,以微信公众平台最新文档为准。可用 uView 表单组件承接用户输入的头像、昵称(使用微信提供的「头像昵称填写能力」时按官方组件要求)。
6.2 手机号(重点)
- 使用
open-type="getPhoneNumber",在@getphonenumber中取code(新版)。 - 明文手机号只能由后端 用微信接口换取;前端禁止存放 AppSecret、
session_key。 - 需小程序资质与后台开通相关能力(如手机号快速验证)。
6.3 与 uView 的配合
- 优先查阅 uView / uView Plus 文档中
u-button的openType说明。 - 若透传不完整,用 原生
button+ 与 uView 一致的 class 是最稳妥做法。
6.4 代码佐证:手机号按钮与回调(微信端)
模板(uView 的 u-button 需支持透传 open-type;否则换成原生 button):
<u-button open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
授权手机号
</u-button>
回调里 只把 code 交给后端 换手机号(示例为前端请求占位,域名需加入小程序合法域名):
onGetPhoneNumber(e) {
// #ifdef MP-WEIXIN
if (e.detail.errMsg === 'getPhoneNumber:ok') {
const code = e.detail.code
uni.request({
url: 'https://你的域名/api/wx/phone',
method: 'POST',
data: { code }
})
} else {
uni.showToast({ title: '用户未授权', icon: 'none' })
}
// #endif
}
服务端使用微信提供的 手机号获取接口 用 code 换明文(具体 URL、参数以微信开放平台当前文档为准),AppSecret、session_key 仅放服务端。
7. uni-app 开发微信小程序的通用注意点
- 条件编译:
#ifdef MP-WEIXIN隔离微信独有 API。 - 样式:注意安全区与 uView 默认间距。
- 网络:配置 request 合法域名。
- 分包:页面多时拆分,控制主包体积(含 uView 按需)。
- Vue2 / Vue3 与 uView 大版本一一对应,勿混装。
7.1 代码佐证:条件编译
仅微信小程序打包的代码(例如 getPhoneNumber、部分 wx 能力)建议包在条件编译里,避免其它端报错:
onGetPhoneNumber(e) {
// #ifdef MP-WEIXIN
if (e.detail.errMsg === 'getPhoneNumber:ok') {
const code = e.detail.code
// ...
}
// #endif
}
模板侧若某组件仅小程序需要,可用 v-if 配合 // #ifdef 在构建期裁剪(具体写法以 uni-app 文档为准)。
8. 说明
main.js、uni.scss、pages.json、manifest.json 与页面 .vue 的参考代码均已以上文 Markdown 代码块 形式给出;在本地用 HBuilderX 或 CLI 创建 uni-app 工程后,按路径新建文件并粘贴即可,无需再维护仓库内独立片段目录。
9. 小结
- 本案例 UI 对接对象为 uView(Vue2 用 uView 2.x,Vue3 用 uView Plus),与 Web 端 iView / View UI 不是同一套。
- 地图与定位 重点在权限、隐私合规与坐标系。
- 手机号 必须前后端配合,前端只传
code。
若将本文迁入博客,可在 frontmatter 中增加分类「技术实践 / 小程序」与日期。
