ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Vue3+Uniapp开源商城芋道商城:从跑通到二开的实战指南

Vue3+Uniapp开源商城芋道商城:从跑通到二开的实战指南

简介:芋道商城是一套基于 Vue3 + Uniapp 构建的 100% 开源电商系统解决方案,面向需要快速搭建商城、开展分销、拼团等营销活动的开发者和企业,也适合希望从实际项目中学习跨端商城架构的中高级前端与全栈人员。系统在基础交易模块之外,集成分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播及页面 DIY 等能力,覆盖新零售/网店商城高频业务场景;底层采用 Uniapp,可编译到 H5、微信小程序及 App 等多端,便于拓展运营触点。资源包为 zip 格式,共 615 个文件,约 2.68MB,其中以 246 个 vue 页面组件、139 个 js 逻辑文件、65 个 json 配置、76 个 md 说明文档为主,辅以 scss 样式、png 图片、ttf 字体等,目录按功能模块划分,可按需查阅。已有 460 人学习下载。通过源码可梳理 Uniapp 多端编译配置、营销模块设计与页面 DIY 的实现思路,也可直接在其上做二次开发,显著降低从零搭建成本。

1. 芋道商城到底是什么:一个能落地的 Vue3 + Uniapp 开源电商底座

芋道商城是那种“能落地”的开源商城:基于 Vue3 + Uniapp 的商城端,一套代码覆盖微信小程序、H5 和 App,后端则把分销、拼团、砍价、秒杀、优惠券、积分、会员等级这些电商里最重的营销能力都做成了独立模块,页面还支持 DIY 拖拽配置。同类项目里演示站做得漂亮的很多,但代码拉下来能直接当开发底座的不多,它算少数派。对工程师来说,这意味着商品、订单、营销三套中心都不用从零搭,直接在现成骨架上改业务就行。适合三类人:要给客户交付小程序商城的接单团队、想借真实项目学 Vue3 和 Uniapp 的开发者、以及需要快速验证电商玩法的产品。下面从本地跑通开始,一路拆到营销模块实现、二次开发避坑和上线前检查。

2. 本地跑通芋道商城:从环境准备到小程序端出画面的完整链路

2.1 工程结构先看清:Vue3 + Uniapp 的商城端、管理后台与后端服务

一个典型的芋道商城仓库里通常有三块东西:商城前端(Vue3 + Uniapp,产物是微信小程序、H5、App),管理后台前端(Vue3 桌面端,给运营配置商品和营销活动),后端服务(Java 系,负责接口、订单、支付和营销规则执行)。不少第一次接触的人把 Uniapp 端当成整个项目,启动时到处找 package.json,找到的却是管理后台的目录,跑起来后一脸懵。

我一般建议动手前先做一次目录测绘,用命令把所有前端工程的位置列出来,确认哪个是商城端、哪个是管理后台;后端则找pom.xml(Maven)或build.gradle(Gradle),这两个文件决定了启动入口在哪。这个动作花不了五分钟,但能避免“装了半天下错依赖”的尴尬。

# 在项目根目录下执行,列出所有含 package.json 的前端工程位置 find . -maxdepth 3 -name "package.json" -not -path "*/node_modules/*" # 确认 node 版本,Vue3 + Vite 对老版本 Node 不友好 node -v # 启用 pnpm,依赖安装速度比 npm 快不少 corepack enable

参数说明:-maxdepth 3限制扫描深度,防止把 node_modules 翻出来;-not -path排除依赖目录。node 版本建议 18 及以上,Vite 5 之后对 18 以下版本基本不兼容,跑起来会直接报语法错误。包管理器优先 pnpm,不只是快,还能避免 npm 在某些复杂依赖树下解析出的版本不一致问题。

先确认工程边界再继续,这是整个跑通流程里最容易被跳过的步骤。很多人第一次跑不起来的原因根本不是环境,而是不知道自己在哪个工程里执行命令。

2.2 后端与数据库初始化:MySQL、Redis 配置里最常改的三个参数

后端服务通常依赖 MySQL 和 Redis:MySQL 放商品、订单、会员、营销活动数据,Redis 承担缓存、验证码、秒杀库存这类需要快速读写的场景。启动前要先把数据库初始化掉。成型项目一般自带 SQL 脚本,导入即可;如果没有脚本,就按实体类反向建表,但芋道这类项目不太需要走这条路。

spring: datasource: url: jdbc:mysql://127.0.0.1:3306/mall?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4 username: root password: 123456 redis: host: 127.0.0.1 port: 6379 password: "" # 本地通常无密码,生产环境务必设置

这份配置里三个参数最常被改,也最容易改完翻车。一是serverTimezone,不设成Asia/Shanghai时订单时间会差 8 小时,排查起来很隐蔽,你会觉得所有时间戳都对不上但找不到原因。二是characterEncoding=utf8mb4,它决定商品名里带 Emoji 或生僻字时能不能正常入库,默认 utf8 会在写库时报错。三是 Redis 密码,本地为空没问题,生产开了密码后,连接串和这里的password要同步改,漏一个就连不上。

改完配置,在后端启动类所在目录执行mvn spring-boot:run,看到 “Started” 日志后访问管理后台地址,能打开登录页就算后端起来了。这里有个高频问题:页面登录时验证码加载不出来或下单提示“缓存服务异常”,八成不是代码问题,先看 Redis 有没有真的连上,尤其是密码没对齐这种情况,排查十分钟起步。

提示:后端启动成功后,先别急着跑前端。用接口文档或浏览器直接访问一个需要登录的接口,确认 token 认证链路是通的,再往下走能省掉不少联调时间。

2.3 商城端跑起来:pnpm 安装依赖与微信开发者工具导入 dist 目录

商城端跑起来有两种方式:HBuilderX 可视化运行,或者 CLI 命令构建后导入微信开发者工具。我更推荐 CLI 方式,因为芋道商城这类 Vue3 项目本质是 Vite 工程,命令行里看到的构建错误比编辑器直观得多,也方便排查依赖问题。

# 进入商城前端目录后执行 pnpm install # 安装依赖,报错先看 registry 是否可用 pnpm dev:mp-weixin # 构建微信小程序产物,输出到 dist/dev/mp-weixin

命令跑完后,打开微信开发者工具选择“导入项目”,目录指向上面输出的dist/dev/mp-weixin,AppID 先用测试号,等真正发布时再换成自己注册的小程序 AppID。页面能加载出来不代表接口通了——商城端依赖后端接口,需要把请求地址配置到本机后端端口,常见做法是在环境变量文件里指定VITE_API_BASE_URL,而不是在代码里硬编码。

小程序端的域名白名单是个容易忽略的限制。本地联调可以在开发者工具里勾选“不校验合法域名”,这只对本地生效;上线前必须在微信公众平台配置正式域名,否则体验版都打不开。这个不要拖到真机调试时才处理,本地页面一亮起来就先确认接口通路。

另外,商城端的manifest.json是很容易被忽略的文件。微信小程序的 AppID、mp-weixin块里的基础库版本、调试开关都集中在这里,CLI 模式下它还影响 Vite 输出的产物配置。第一次跑通后建议把manifest.json里的内容过一遍,尤其是 AppID 和权限声明,避免真机调试时再返工。

3. 看懂商城端的 Vue3 + Uniapp 代码:请求封装、登录与下单主流程

3.1 模块怎么分:pages、api、store、components 的边界

商城端的目录结构通常是清晰的水平分层:pages按业务分页,商品、订单、购物车、营销专题各占一块;api目录每个模块一个文件,对应后端接口的封装;store(Pinia)放登录态、购物车、全局配置;components放跨页复用的组件。新人容易犯的毛病是把所有请求都写在页面里,页面一多、后端接口一改,查找调用关系就成了体力活。

我一般要求团队遵循一个约定:页面里只允许调用api目录导出的函数,不允许直接用uni.request。这个约束的价值在联调阶段最明显——接口报错时能清楚知道是哪一层的问题,而且统一封装可以集中处理登录态和错误提示。

// src/api/request.js —— 商城端统一的请求封装 const BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api' export function request(options) { return new Promise((resolve, reject) => { uni.request({ url: BASE_URL + options.url, method: options.method || 'GET', data: options.data || {}, header: { token: uni.getStorageSync('token') || '', 'content-type': 'application/json', }, success: (res) => { // 后端统一返回结构:code 为 0 表示成功,401 表示登录过期 if (res.data.code === 0) { resolve(res.data.data) } else if (res.data.code === 401) { uni.removeStorageSync('token') uni.navigateTo({ url: '/pages/login/index' }) reject(res.data) } else { uni.showToast({ title: res.data.msg || '请求失败', icon: 'none' }) reject(res.data) } }, fail: reject, }) }) }

这里有几个参数要说明。BASE_URL用import.meta.env是 Vite 的标准写法,同一个工程通过不同环境变量文件切换后端地址,不用改业务代码。token 每次从 storage 读取而不是启动时读一次,是因为用户可能多端登录导致 token 被刷新,写死在变量里会拿到旧值。401 的统一处理放在请求层,页面里就不用到处写“去登录”的逻辑,这是商城工程里最常见的收敛方式。

3.2 微信登录换 token:uni.login 拿到 code 之后的去向

小程序端登录链路是固定的:调uni.login拿临时凭证 code,把 code 交给后端,后端拿 code 向微信服务器换 openid,再生成自己的 token 返回给前端。很多第一次做的人误以为uni.login返回的就是 openid,直接把返回值存本地——这是误区。code 有效期很短且只能用一次,必须后端去换。

// src/api/auth.js export async function wxLogin() { // 1. 拿临时凭证,小程序端 provider 固定为 weixin const res = await uni.login({ provider: 'weixin' }) if (res.errMsg !== 'login:ok') { throw new Error('微信登录失败,请重试') } // 2. 后端拿 code 换 openid 并返回自建 token const { token } = await request({ url: '/member/auth/login-by-weixin', method: 'POST', data: { code: res.code }, }) uni.setStorageSync('token', token) return token }

这里的三个细节容易踩坑:一是uni.login可能因用户隐私授权问题返回失败,要判断errMsg,不要直接解构;二是 code 原样传给后端即可,不需要encodeURIComponent,后端在服务端请求微信接口时会处理编码,前端多此一举反而可能导致参数对不上;三是登录成功后最好再拉一次用户信息,芋道这类带会员等级的项目,页面顶部会展示等级和积分,这些数据通常和登录态一起返回,前端可以缓存在 Pinia 里,避免每次进页面都请求一遍。

3.3 从加购到下单:前端防重复提交与订单参数传递

下单是商城核心链路,前端能控制的只有两件事:请求不重复、参数不缺失。真正保证“一次订单只扣一次库存”的是后端事务与幂等,但前端如果连点击都防不住,再好的后端也会被用户的连点打穿。

// pages/order/confirm/index.vue —— 极简的提交片段 let submitting = false async function submitOrder() { if (submitting) return submitting = true try { const data = await request({ url: '/trade/order/create', method: 'POST', data: { skuId: this.skuId, count: this.count, couponId: this.couponId || undefined, remark: this.remark.trim(), }, }) uni.navigateTo({ url: `/pages/order/pay?orderId=${data.orderId}` }) } finally { // 无论成功与否都要释放按钮锁,否则用户被卡死在页面 submitting = false } }

代码里的submitting是前端锁,finally里释放,保证请求失败后用户可以重试。业务上要注意:couponId传undefined时uni.request会把该字段从请求体里拿掉,有些后端对空字段校验很严格,拿不准时不如显式传0,让后端去判断。下一单的凭证是后端返回的orderId,支付页只拿它换支付参数,前端不要拼价格——价格一定以后端为准,前端算出的金额只用于展示,这是做商城的基本底线。

确认订单页的数据(商品快照、可用优惠券、积分可抵金额)应该从后端一次性拉取并在进入页面时缓存。如果拆成地址、商品、运费、优惠券四个接口并发请求,每个响应时间不一致,页面会闪。常见做法是后端提供聚合接口“查询结算信息”,前端只调一次;若后端没做聚合,也要用Promise.all把并发请求收敛,避免页面出现一半数据加载完、一半还在转圈的状态。

4. 营销玩法拆解:分销、拼团、砍价、秒杀、优惠券与积分是怎么实现的

4.1 分销关系与佣金计算:按实付金额分层,在确认收货时结算

分销的落点通常是一张用户扩展表或邀请关系表:每个用户记录推荐人inviter_id,注册时写死,下单后顺着关系向上找一二级推荐人。佣金口径最容易出错的地方是“按什么金额算”。常见做法分两种:按商品原价算,或按订单实付金额算。我推荐后者,原价口径在促销满天飞的商城(满减、优惠券、秒杀)里会算出一大堆不合理的佣金;按实付金额(扣除优惠券、积分抵扣,运费一般不计)更接近利润感知。

// 订单确认收货后触发佣金结算(伪代码) function settleCommission(order) { const buyer = getUser(order.userId) const level1 = getUser(buyer.inviterId) // 一级:直接推荐人 const level2 = level1 && getUser(level1.inviterId) // 二级 const { level1Rate, level2Rate } = getCommissionConfig(order.skuId) // 实付金额 = 订单总金额 - 优惠券抵扣 - 积分抵扣 - 运费 const base = order.payAmount if (level1 && level1Rate > 0) { addBalance(level1.id, base * level1Rate, '一级分销佣金', order.id) } if (level2 && level2Rate > 0 && order.includeLevel2 === 1) { addBalance(level2.id, base * level2Rate, '二级分销佣金', order.id) } }

这里有几个业务参数必须先定死:一级比例、二级比例、是否计算二级、佣金入账时间。结算时机我坚持放在“确认收货”而不是“支付成功”,因为支付后可能退款,佣金发了再往回扣会牵扯余额变动,很容易对不上账。芋道这类商城常见的做法也是订单完成后结算,二开时别为了“让用户快点看到收益”改成支付即结算——售后一多,账就乱了。

会员等级和分销经常被混在一起。等级通常单独一张表,按累计消费金额或积分升降级,影响的是折扣率、积分倍率这些权益;分销影响的是推荐关系里的佣金。两者是两套体系。同时计算折扣和佣金时,活动叠加可能让订单利润变负,建议在营销配置里加一个互斥/叠加的开关,每个订单活动之间先算一次叠加优先级。

4.2 拼团、砍价、秒杀:三种并发策略与库存校验差异

这三个营销功能都涉及“很多人同时操作一个商品”,但后台逻辑完全不同。

秒杀是高并发下的库存强校验,核心是防超卖。常见做法是把库存预热到 Redis,扣库存用 Lua 脚本保证原子性,扣减成功才允许下单。拼团的重点是成团校验而非抢库存:一个人参团锁定一个库存位,达到成团人数即成团,超时未成团自动退款。砍价不涉及并发,但涉及风控:砍价策略是一张递减幅度表,首刀力度大,之后随机递减;还要防一个人反复砍价,通常限制每个用户对同一商品只能砍一次,或者每天只能帮砍 N 次。

// 秒杀扣库存的常见做法:Redis + Lua 脚本保证不超卖 const script = ` local stock = tonumber(redis.call('get', KEYS[1]) or '0') if stock >= tonumber(ARGV[1]) then redis.call('decrby', KEYS[1], ARGV[1]) return 1 end return 0 ` const ok = await redis.eval(script, [stockKey], [1]) if (!ok) { throw new Error('手慢了,商品已抢光') } // 扣减成功后,再在 MySQL 里生成订单,并用订单号做幂等

参数说明:KEYS[1]是秒杀场次的库存 key,ARGV[1]是本次购买数量,脚本保证库存判断和扣减在 Redis 里原子完成。这里有个绕不开的坑:Redis 库存扣了,但 MySQL 订单创建失败,会出现“库存没了、订单没生成”。行业通用做法是把 Redis 扣减当预扣,订单创建失败时回补库存;或者下单前先在 MySQL 里预占一个库存位,再把这个预占逻辑同步到 Redis。芋道这类开源商城一般采用的是可回补方案,二开时千万别把这两步的先后顺序调反。

拼团的成团校验用一句话概括:团单存团 ID,团员订单关联团 ID,成团判断就是查团 ID 下的支付成功订单数是否达到目标人数。砍价的核心参数则是三件套:起砍价、底价、每刀区间。三个参数定下来,砍价算法就能收敛,剩下的只是随机函数落在哪个区间。

4.3 优惠券与积分组合扣减:顺序固定,条件更新回滚

优惠券与积分在订单里往往同时存在,用户既用券,又用积分抵现金。后端收到的组合是“订单金额 - 优惠券金额 - 积分抵扣金额 = 实付金额”。这一节最容易出错的是扣减顺序和事务一致性。

常见做法是固定顺序:先核销优惠券,再扣积分,最后生成订单。每一步都必须是条件更新,SQL 的WHERE里带上可用性判断,更新后判断影响行数,不满足直接回滚。

-- 1. 核销优惠券:used_count + 1 必须不超过 total_count UPDATE coupon_instance SET status = 1, used_time = NOW() WHERE id = #{couponInstanceId} AND user_id = #{userId} AND status = 0; -- 2. 扣积分:账号余额必须够 UPDATE user_points SET points = points - #{deduction} WHERE user_id = #{userId} AND points >= #{deduction};

上面两条 SQL 每一条都要求影响行数等于 1,任何一条返回 0 都要抛异常并回滚整个事务。积分扣减的points >= deduction条件漏掉,就会出现积分扣成负数;优惠券则要判断状态字段,防止一张券被并发请求用两次。这套逻辑放在数据库事务里执行,隔离级别保持默认即可,不需要为了这个特意调高。

组合支付的业务细节也要注意:优惠券、积分、余额属于前置资产,微信支付属于外部支付。代码逻辑里一般先处理前置资产,再发起微信支付;微信支付失败或取消时,前置资产要回滚。反过来,如果先发起微信支付再核销优惠券,支付成功后券却核销失败,就会造成“钱付了、券还在”的尴尬局面,客诉处理起来极其被动。

5. 二开避坑:小程序登录手机号、支付回调、页面 DIY 和日志的四个重灾区

5.1 获取手机号:必须走 button open-type,别查老接口

现象:在小程序里直接调uni.getPhoneNumber,或者在onLoad里想通过一个 code 换手机号,拿到的是失败回执。

原因:微信把手机号快速验证组件收紧了。现在必须由用户主动点击带有open-type="getPhoneNumber"的 button 才能触发授权,并且返回的不再是明文手机号,而是一次性动态令牌 code。

解决:把“一键登录”按钮改成下面这种结构,前端拿到 code 后交给后端换取。

<button open-type="getPhoneNumber" @getphonenumber="onGetPhone">微信一键登录</button>
async function onGetPhone(e) { if (e.detail.errMsg !== 'getPhoneNumber:ok') return const { token } = await request({ url: '/member/auth/phone-login', method: 'POST', data: { code: e.detail.code }, }) uni.setStorageSync('token', token) }

补充一个坑:网上能搜到一些旧教程,让你直接使用e.detail.phoneNumber,这在旧版本里可行,现在这个字段通常是undefined。验证方式是在真机上测试,不要只依赖开发者工具,工具里模拟的授权环境和真机体感完全不同。

5.2 支付回调验签:本地调试用临时通道,收到先验签再改单

现象:本地起的后端,下单后跳微信支付,支付成功后订单状态一直是“待支付”,回调怎么都收不到。

原因:微信支付回调必须由微信服务器主动访问你的接口,而微信服务器访问不到本机的localhost。要收到回调,回调地址必须能被公网访问。

解决:常见做法是把回调地址配到一条临时公网通道上,让微信服务器访问这条通道,再转发到本地后端。注意两条底线:第一,这条通道只用于本地联调,上线前必须改为正式域名;第二,回调接口第一件事是验签,验签通过才更新订单,失败直接返回失败。

// 回调接口骨架 async function wechatPayNotify(req, res) { const rawBody = req.rawBody // 原始报文,验签必须用它 const signature = req.headers['wechatpay-signature'] const serial = req.headers['wechatpay-serial'] if (!verifySignature(rawBody, signature, serial)) { return res.send('fail') // 验签失败,微信会重试 } const { out_trade_no, trade_state } = parseBody(req.body) if (trade_state === 'SUCCESS') { // 更新订单时要带幂等条件:状态为待支付才更新 await markOrderPaid(out_trade_no) } res.send('success') }

易错点有两个。一是验签用的报文必须是原始请求体,任何格式化、序列化都会导致签名对不上。实际项目里通常用express.raw({ type: '*/*' })或等价方式拿到原始串,而不是req.body转 JSON 后再验。二是更新订单时加“状态为待支付”的条件,微信支付成功后可能推送多次通知,接口要天然幂等,否则重复通知会把订单处理两次。

5.3 页面 DIY 配置改完不生效:缓存、版本号、组件 key 三查

现象:在管理后台里拖拽页面组件、调整排序,保存后小程序端看起来完全没有变化,多刷几次偶尔生效。

原因:页面 DIY 渲染的是配置面板生成的 JSON,小程序端加载配置时会走缓存。发布新版本时如果前端没做版本号校验,旧的缓存配置会一直覆盖新配置。

解决:按顺序查三处。一查管理后台的缓存键,确认保存时有没有清旧缓存;二查小程序端拉取 DIY 配置的请求有没有带版本号参数,后端应返回递增的version,前端本地配置与它不一致时强制刷新;三查组件注册表——DIY 面板里保存的是组件 key(如goods-list、banner),小程序端渲染组件时按 key 匹配,如果后端配置里的组件名和前端注册的名字对不上,渲染器会静默跳过,页面看起来就是“没改”。

// 拉取 DIY 配置时带版本号,本地不一致则重新拉取 const { config, version } = await request({ url: '/diy/page/detail', data: { pageId } }) if (localVersion !== version) { uni.setStorageSync('diy_config', JSON.stringify(config)) uni.setStorageSync('diy_version', version) } // 渲染器根据 config.components 数组逐项渲染 // 未匹配的组件打印 warn,而不是静默跳过

这里最容易翻车的是“静默跳过”:渲染器对未知组件不报错,配置无效时无从下手。建议二次开发时在渲染循环里加console.warn,能直接看到哪块组件没渲染出来,排查速度能快一个量级。

5.4 真机与开发者工具里不打印日志:先开调试,再查构建配置

现象:代码里到处是console.log,但微信开发者工具和真机上什么都看不到,Vue3 项目有时连报错都不显示。

原因:常见诱因有三种。一是微信开发者工具默认关闭了调试信息,需要手动开启调试模式;二是发布或体验版构建时,压缩工具把console.*干掉了;三是 Vue3 + Uniapp 的日志打印通道在某些基础库版本下不稳定,日志被过滤或显示为灰色。

解决:按顺序排查。先在手机端打开调试模式,再到manifest.json的mp-weixin配置块确认基础库版本和调试开关,最后查 Vite 或打包配置,确认有没有开启移除 console 的压缩选项。

{ "mp-weixin": { "appid": "你的小程序appid", "setting": { "urlCheck": false, "es6": true, "postcss": true, "minified": false } } }

minified设为 false 是为了本地排查问题,上线前改回 true,并配合压缩把 console 移除,避免日志带进生产包。这个“不打印日志”的高频问题和玄学差不多,九成以上是工具开关或构建配置,不是代码问题——遇到先开调试面板,再怀疑构建,别一开始就改业务代码。

6. 把芋道商城变成自己的:二开顺序、上线前检查和一个小技巧

6.1 二开顺序:打通登录链路,再动营销,最后碰页面 DIY

开源商城最容易让二开团队返工的是改动顺序不对。一上来就改页面 DIY 或营销规则,联调时发现登录、支付、订单链路没跑通,所有改动都悬在空中。我一般按这样的顺序推进:先跑通“小程序登录 → 下单 → 支付 → 回调 → 订单状态变化”这条主链路,再在管理后台配置一个最简单的优惠券活动验证营销模块,最后才动页面 DIY。原因是登录和支付是全局依赖,先打通,后面每一处改动都能围绕真实订单验证。

6.2 上线前检查:AppID、域名白名单、隐私协议与安卓包

上线检查最容易漏的是三处。小程序 AppID 必须换成自己注册的正式 AppID,开发工具里用测试号跑通后,换成正式号接口报 401 是常态,因为后端配置的 AppID 和密钥对不上。第二个是域名白名单:小程序 request 合法域名要求已备案且配置 HTTPS,本地联调时勾选的“不校验合法域名”上线前必须关闭,否则页面全部请求失败。第三个是隐私协议,涉及手机号登录和支付的项目都要在微信后台配置用户隐私保护指引,否则审核会被打回。如果还要上架安卓应用市场,manifest.json里的包名、版本号和应用图标要提前定好,这些字段在审核时不能随意改,改动要重新提审。

6.3 一个技巧:分享裂变用小程序码加 scene,别在 path 里塞参数

分销场景下,分享出去的卡片要带上推荐人关系。常见新手做法是把inviterId直接拼到 path 里,比如/pages/goods/index?id=1&inviterId=88。这种做法普通分享里能用,但生成小程序码、扫码进入时微信会强制走scene参数,路径参数会丢。稳妥的方式是把分销关系放进scene,进入页面后统一解析。

onLoad(options) { // 小程序码携带的 invite_id 走 scene,且需要 decodeURIComponent if (options.scene) { const params = decodeURIComponent(options.scene) // 形如 invite_id=88 const inviterId = params.split('=')[1] uni.setStorageSync('inviter_id', inviterId) } // 普通微信分享时仍可用 path 参数 if (options.inviterId) { uni.setStorageSync('inviter_id', options.inviterId) } }

scene 有长度限制,通常只放关键 ID,不要把订单摘要、商品参数堆进去。这是我们团队真实踩过的坑:最初把整套促销信息塞进分享参数,encode 后超长,生成的小程序码打不开页面,查了半天才发现是 scene 超限。养成习惯后,分销跳转一律走 scene 加解码,稳定得多。希望这些经验能帮你在芋道商城上少走弯路。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进