uniapp 从入门到精通:第5章 5.1 微信小程序原生能力
🎯 开场:为什么你写的 App 总是"差点意思"?
上一章我们搞定了电商首页和商品详情,页面漂漂亮亮的,用户也能下单了。但你有没有这种感觉——
"页面是有了,但总像个空壳子,不像一个真正的 App"
比如:
- 别人的小程序能一键微信登录,你的只能输账号密码
- 别人能分享商品到朋友圈,你点分享没反应
- 别人的 App 能调起微信支付,你的只能"请联系客服"
这些不是页面问题,是 原生能力 没接上!
说白了:页面是皮,原生能力是骨。没有骨头,皮再漂亮也是个软脚虾。
本章学完,你能:
1. 让用户一键微信登录(不用记密码)
2. 实现分享功能(让用户帮你拉新)
3. 摸到支付的门把手(下一章会细讲)
🧱 基础:UniApp 原生能力是个啥?
5.1.1 什么是原生能力?
先打个比方:
你的小程序就像一家餐厅:
- 前端页面 = 餐厅的装修和菜单(好看很重要)
- 原生能力 = 厨房设备\n\n
\n\n
\n\n + 服务员(能上菜、能接待、能收款)
UniApp 本身是个"通用厨房",但微信小程序有自己独家的设备:
- 微信登录(只用微信的人,你的 App 也能用他的微信账号)
- 微信支付(收钱用的)
- 分享到微信群/朋友圈(免费推广)
- 获取用户微信头像昵称(不用用户再填)
5.1.2 UniApp 怎么调用原生能力?
UniApp 封装了一套 uni.xxx API,不管你打包到哪个平台,都能用同一套代码。
但!有些能力只有微信小程序支持,这时候就要用条件编译——
// 微信小程序专属能力
#ifdef MP-WEIXIN
uni.login({
success: (res) => {
console.log('登录成功', res.code)
}
})
#endif
这段代码的意思是:只有打包成微信小程序时才编译这段代码,其他平台跳过。
简单理解:UniApp 是个翻译官,原生能力是方言。有些话(通用 API)它能翻所有平台;有些话(微信专属)只有翻译成"微信话"才有人听得懂。
5.1.3 四大金刚:login / getUserProfile / share / payment
UniApp 调用微信原生能力,主要靠这 4 个:
| API | 干啥的 | 类比 |
|---|---|---|
uni.login() |
获取微信登录凭证 | 拿身份证号(临时证明你是微信用户) |
uni.getUserProfile() |
获取用户头像昵称 | 查户口本 |
uni.share() |
分享内容 | 发传单 |
uni.requestPayment() |
微信支付 | 刷卡收款 |
🔥 实战:三个小项目搞定原生能力
项目 1:一键微信登录(5 分钟)
场景:用户打开 App,直接弹出微信登录,用户授权后显示头像。
// pages/index/index.vue
<template>
<view class="container">
<!-- 未登录状态 -->
<view v-if="!hasLogin" class="login-box">
<button type="primary" @click="handleWxLogin">微信一键登录</button>
</view>
<!-- 已登录状态 -->
<view v-else class="user-info">
<image class="avatar" :src="userInfo.avatarUrl"></image>
<text class="nickname">{{ userInfo.nickName }}</text>
<text class="welcome">欢迎回来!</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
hasLogin: false,
userInfo: {
nickName: '',
avatarUrl: ''
}
}
},
methods: {
// 微信登录核心代码
handleWxLogin() {
// 第一步:获取登录凭证
uni.login({
provider: 'weixin', // 明确指定微信
success: (loginRes) => {
console.log('登录凭证:', loginRes.code) // 临时凭证,发给后端换 token
// 第二步:获取用户信息(头像昵称)
uni.getUserProfile({
desc: '用于展示用户头像和昵称', // 必填!微信审核要看的
success: (profileRes) => {
console.log('用户信息:', profileRes.userInfo)
this.userInfo = profileRes.userInfo
this.hasLogin = true
// 这里应该调用后端接口,用 code 换真正的 token
// this.getTokenFromBackend(loginRes.code)
},
fail: () => {
uni.showToast({ title: '需要授权才能登录', icon: 'none' })
}
})
},
fail: () => {
uni.showToast({ title: '微信登录失败', icon: 'none' })
}
})
}
}
}
</script>
<style>
.container { padding: 40rpx; }
.login-box { margin-top: 200rpx; text-align: center; }
.user-info { text-align: center; margin-top: 200rpx; }
.avatar { width: 160rpx; height: 160rpx; border-radius: 50%; }
.nickname { display: block; font-size: 36rpx; margin: 20rpx 0; }
.welcome { color: #999; }
</style>
运行效果:
- 点击按钮 → 弹出微信授权框 → 用户点"允许" → 显示头像和昵称
这代码干了啥:
- uni.login() 拿到一个临时 code,发给后端换真正的登录态
- uni.getUserProfile() 获取用户头像昵称(用户必须手动点"允许")
注意!2023 年后微信改了规则,
getUserProfile必须用户主动触发,不能自动弹!别想着偷偷获取用户信息了。
项目 2:商品详情页分享(15 分钟)
场景:用户看完商品详情,点分享按钮,能把商品卡片分享到微信群/朋友圈。
// pages/goods-detail/goods-detail.vue
<template>
<view class="detail-page">
<image class="goods-img" :src="goods.image"></image>
<view class="goods-info">
<text class="title">{{ goods.name }}</text>
<text class="price">¥{{ goods.price }}</text>
<text class="desc">{{ goods.description }}</text>
</view>
<!-- 分享按钮 -->
<button class="share-btn" plain @click="handleShare">分享给好友</button>
</view>
</template>
<script>
export default {
data() {
return {
goods: {
id: '001',
name: '阳光玫瑰葡萄 2斤装',
price: 59.9,
description: '当季新鲜水果,颗颗饱满,香甜多汁',
image: '/static/grape.jpg'
}
}
},
onShareAppMessage() {
// 配置分享内容(右上角三点菜单的分享)
return {
title: this.goods.name, // 分享标题
desc: this.goods.description, // 分享描述
imageUrl: this.goods.image, // 分享封面图
path: `/pages/goods-detail/goods-detail?id=${this.goods.id}` // 点开后的页面
}
},
onShareTimeline() {
// 配置分享到朋友圈
return {
title: `【限时特惠】${this.goods.name} 仅需¥${this.goods.price}`,
query: `id=${this.goods.id}` // 携带商品 ID
}
},
methods: {
handleShare() {
// 调起内置分享面板
uni.showShareMenu({
withShareTicket: true, // 带上群票据(可用于判断分享到哪个群)
menus: ['shareAppMessage', 'shareTimeline'] // 分享给好友 / 分享到朋友圈
})
// 注意:实际调起分享是用户点右上角...菜单,这里只是开启开关
}
}
}
</script>
<style>
.detail-page { padding: 30rpx; }
.goods-img { width: 100%; height: 500rpx; border-radius: 16rpx; }
.goods-info { padding: 30rpx 0; }
.title { font-size: 36rpx; font-weight: bold; display: block; }
.price { color: #ff4d4f; font-size: 40rpx; display: block; margin: 20rpx 0; }
.desc { color: #666; line-height: 1.6; }
.share-btn { margin-top: 60rpx; }
</style>
运行效果:
- 用户点按钮 → 开启分享菜单
- 用户点右上角「...」→「发送给朋友」→ 好友看到商品卡片
- 用户点右上角「...」→「分享到朋友圈」→ 朋友圈显示商品信息
关键点解释:
- onShareAppMessage = 监听"发送给好友"事件,返回分享配置
- onShareTimeline = 监听"分享到朋友圈"事件
- uni.showShareMenu() = 在代码里主动开启分享按钮(默认可能不显示)
说白了:分享就是"帮你发传单"。你把传单内容(标题、图片、链接)准备好,微信帮你发。
项目 3:购物车订单汇总生成器(15 分钟)
场景:用户把商品加入购物车后,生成一份订单汇总,可以分享给朋友帮忙付款。
// pages/cart/cart.vue
<template>
<view class="cart-page">
<!-- 购物车列表 -->
<checkbox-group @change="onCheckChange">
<view v-for="item in cartItems" :key="item.id" class="cart-item">
<checkbox :value="item.id" :checked="item.checked"></checkbox>
<text class="item-name">{{ item.name }}</text>
<text class="item-price">¥{{ item.price }} × {{ item.num }}</text>
</view>
</checkbox-group>
<!-- 订单汇总 -->
<view class="order-summary">
<text>共 {{ selectedCount }} 件商品</text>
<text class="total-price">合计:¥{{ totalPrice }}</text>
<button type="warn" size="mini" @click="generateOrderShare">生成付款链接</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
cartItems: [
{ id: '1', name: '阳光玫瑰葡萄', price: 59.9, num: 2, checked: true },
{ id: '2', name: '有机草莓', price: 35.0, num: 1, checked: true },
{ id: '3', name: '智利车厘子', price: 88.0, num: 1, checked: false }
]
}
},
computed: {
selectedItems() {
return this.cartItems.filter(item => item.checked)
},
selectedCount() {
return this.selectedItems.reduce((sum, item) => sum + item.num, 0)
},
totalPrice() {
return this.selectedItems.reduce((sum, item) => sum + item.price * item.num, 0).toFixed(2)
}
},
methods: {
onCheckChange(e) {
const selected = e.detail.value
this.cartItems.forEach(item => {
item.checked = selected.includes(item.id)
})
},
// 生成订单分享信息
generateOrderShare() {
if (this.selectedCount === 0) {
uni.showToast({ title: '请先选择商品', icon: 'none' })
return
}
const orderData = {
items: this.selectedItems.map(i => `${i.name}×${i.num}`).join('、'),
total: this.totalPrice,
time: new Date().toLocaleDateString()
}
// 方式1:生成分享数据(点开小程序查看订单)
uni.showShareMenu({
withShareTicket: true,
menus: ['shareAppMessage', 'shareTimeline']
})
uni.showToast({
title: '已生成链接,可分享给好友',
icon: 'success'
})
// 方式2:复制订单信息(用于微信外传播)
uni.setClipboardData({
data: `【订单汇总】${orderData.items}\n合计:¥${orderData.total}\n下单时间:${orderData.time}`,
success: () => {
uni.showToast({ title: '订单已复制,去分享吧', icon: 'none' })
}
})
// 实际项目中,这里应该调用后端生成真实订单,返回订单号
console.log('当前订单汇总:', orderData)
}
},
onShareAppMessage() {
const selected = this.selectedItems
if (selected.length === 0) return {}
return {
title: `帮我付款!订单合计¥${this.totalPrice}`,
desc: `订单包含:${selected.map(i => i.name).join('、')}`,
path: '/pages/cart/cart?from=share'
}
}
}
</script>
<style>
.cart-page { padding: 30rpx; }
.cart-item { display: flex; align-items: center; padding: 20rpx 0; border-bottom: 1rpx solid #eee; }
.item-name { flex: 1; margin-left: 20rpx; }
.item-price { color: #ff4d4f; }
.order-summary {
position: fixed; bottom: 0; left: 0; right: 0;
display: flex; align-items: center; padding: 30rpx;
background: #fff; box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.1);
}
.total-price { flex: 1; text-align: right; color: #ff4d4f; font-size: 36rpx; font-weight: bold; margin-right: 20rpx; }
</style>
运行效果:
- 用户勾选商品 → 显示合计价格
- 点击「生成付款链接」→ 复制订单文字 → 分享到微信
这代码干了啥:
- computed 计算选中的商品和总价
- uni.setClipboardData() 把订单复制到剪贴板(方便微信外传播)
- onShareAppMessage 分享到微信好友时显示订单信息
例子:就像你去奶茶店点单,店员说"要不要生成订单链接发给朋友,让他帮你付?"——这就是把付款能力分享出去。
💪 进阶:踩坑 + 调试技巧
坑 1:getUserProfile 调不通?授权描述没写!
// ❌ 错误:desc 参数缺失,直接报错
uni.getUserProfile({
success: (res) => { /* ... */ }
})
// ✅ 正确:desc 是必填项,要写清楚用途
uni.getUserProfile({
desc: '用于完善会员资料', // 必须写!不然微信直接拒绝
success: (res) => { /* ... */ }
})
坑 2:分享图片不显示?尺寸不对!
// ❌ 错误:用了本地图片(分享时图片不展示)
imageUrl: '/static/grape.jpg'
// ✅ 正确:分享图片要用线上地址,或者用 canvas 生成分享图
imageUrl: 'https://your-server.com/images/grape.jpg'
坑 3:onShareAppMessage 不生效?检查 pages.json!
// pages.json - 开启当前页面的分享功能
{
"pages": [
{
"path": "pages/goods-detail/goods-detail",
"style": {
"enableShareAppMessage": true, // 开启分享给好友
"enableShareTimeline": true // 开启分享到朋友圈
}
}
]
}
坑 4:login 的 code 只能一次性使用!
// ❌ 错误:同一个 code 用了两次
uni.login({
success: (res) => {
myRequest1(res.code) // 用 code 换 token
myRequest2(res.code) // code 已经失效了!
}
})
// ✅ 正确:code 只能用一次,要用就得重新 login
let currentCode = null
uni.login({
success: (res) => {
currentCode = res.code
myRequest1(currentCode) // 这次用的是同一个 code
}
})
// 下次分享时重新获取 code
坑 5:支付回调可能是假的!
微信支付成功后,success 回调只是"前端发起成功",不等同于真正支付成功。后端必须收到微信的支付回调通知才算数。
// ❌ 错误:前端回调就确认收款
uni.requestPayment({
success: () => {
this.updateOrderStatus('已支付') // 不安全!可能是假的
}
})
// ✅ 正确:以后端回调为准,前端只是引导用户
uni.requestPayment({
success: () => {
uni.showToast({ title: '支付成功,等待确认...', icon: 'none' })
},
fail: () => {
uni.showToast({ title: '支付取消', icon: 'none' })
}
})
调试技巧:看日志的正确方式
// 基础:console.log(开发时用)
console.log('login 结果:', res)
// 进阶:uni.showToast(看运行时数据)
uni.showToast({ title: JSON.stringify(res), icon: 'none', duration: 3000 })
// 生产环境:封装日志请求,发送到服务器
function logToServer(msg) {
// 实际项目里应该发到自己的日志服务
console.warn('[日志]', msg)
}
✏️ 练习题
练习 1(2 分钟):改改登录提示语
- 输入:在项目 1 中,把「需要授权才能登录」的提示改成「拒绝授权就无法使用哦」
- 预期输出:点击拒绝后,toast 显示新提示语
- 提示:找到 fail 回调里的 title 参数
练习 2(3 分钟):加个登录条件
- 输入:在项目 1 中,只有用户昵称包含「小」字才显示「欢迎回来」,否则显示「很高兴认识你」
- 预期输出:不同昵称显示不同欢迎语
- 提示:用 if 判断 this.userInfo.nickName.includes('小')
练习 3(10 分钟):换个商品数据
- 输入:用练习题 2 的登录代码 + 项目 2 的分享代码,实现:登录后用户可分享自己选中的商品
- 预期输出:分享出去的卡片显示用户头像 + 商品信息
- 提示:onShareAppMessage 里可以访问 this.userInfo
练习 4(15 分钟):购物车勾选反选
- 输入:在项目 3 中,添加一个「全选/取消全选」按钮
- 预期输出:点全选所有商品被勾选,再点取消全选
- 提示:给全选按钮绑定事件,遍历 cartItems 设置 checked 状态
练习 5(5 分钟):看图找错
- 输入:以下代码点击分享后,分享出去的卡片没有图片,是哪里的问题?
onShareAppMessage() {
return {
title: '超好吃的葡萄',
imageUrl: '/static/grape.png', // 本地图片
path: '/pages/index/index'
}
}
- 预期输出:说出原因并给出解决方案
- 提示:参考进阶坑 2
作业:做一个「商品测评分享工具」
小明想在朋友圈卖自家种的苹果,需要一个分享工具。
需求描述:
用户输入苹果的品种、价格、口感描述,选择苹果图片,生成一个精美的分享卡片,可以分享到朋友圈。
功能点:
1. 表单输入:品种(文本)、价格(数字)、口感描述(多行文本)
2. 图片选择:调用 uni.chooseImage 选择苹果照片
3. 分享功能:点击分享,生成带图分享到朋友圈
加分项:
1. 添加「预览」按钮,先看效果再分享
2. 记录历史分享记录(存本地 uni.setStorage)
验收标准:
- 能输入表单并选择图片
- 点击分享后,朋友圈能看到带图分享
- 代码有适当注释
📚 总结 + 资源
本文学了 3 件事:
1. uni.login + uni.getUserProfile 实现微信一键登录
2. onShareAppMessage + onShareTimeline 实现分享到好友/朋友圈
3. 条件编译 <!-- #ifdef MP-WEIXIN --> 让代码只在微信小程序生效
延伸学习:
- UniApp 官方文档 - 微信小程序能力
- 微信小程序分享文档
- 《UniApp 跨平台开发实战》相关章节
互动钩子:
你在做微信登录时,被用户拒绝过授权吗?怎么处理的?评论区聊聊老粉优先回复!
彩蛋预告:下一章我们要解决一个大问题——「小程序太大了加载慢怎么办?」学会分包加载,让你的 App 启动快到飞起!

评论(0)