uniapp+vant-weapp 开发小程序踩坑实录
引子
N年前开发小程序用的是taro,但因为好多年没用了,反正也是从0搞,随机挑选了听的比较多uniapp开发,实际用起来虽然和vue3差不多,但还是因为兼容问题遇到很多坑。
- uniapp-3.0.0
- Vue-3.4.21
- Vite-5.2.9
- Vant-weapp-1.11.7
微信小程序获取用户信息
自 2022 年 10 月 25 日 24 时后(以下统称 “生效期” ),用户头像昵称获取规则将进行如下调整:
- 自生效期起,小程序 wx.getUserProfile 接口将被收回:生效期后发布的小程序新版本,通过 wx.getUserProfile 接口获取用户头像将统一返回默认灰色头像,昵称将统一返回 “微信用户”。生效期前发布的小程序版本不受影响,但如果要进行版本更新则需要进行适配。
- 自生效期起,插件通过 wx.getUserInfo 接口获取用户昵称头像将被收回:生效期后发布的插件新版本,通过 wx.getUserInfo 接口获取用户头像将统一返回默认灰色头像,昵称将统一返回 “微信用户”。生效期前发布的插件版本不受影响,但如果要进行版本更新则需要进行适配。通过 wx.login 与 wx.getUserInfo 接口获取 openId、unionId 能力不受影响。
- 「头像昵称填写能力」支持获取用户头像昵称:如业务需获取用户头像昵称,可以使用「头像昵称填写能力」(基础库 2.21.2 版本开始支持,覆盖iOS与安卓微信 8.0.16 以上版本),具体实践可见下方《最佳实践》。
原先用getUserInfo、getUserProfile获取用户信息的方式都废弃了,即使加密信息解密也都是微信用户、灰色头像(别问,问就是全踩了一次,我不理解都废弃了还放在开发文档干啥)。目前只能通过用户手动填写收集用户信息。
头像选择
需要将 button 组件 open-type
的值设置为 chooseAvatar
,当用户选择需要使用的头像之后,可以通过 bindchooseavatar
事件回调获取到头像信息的临时路径。
昵称填写
需要将 input 组件 type
的值设置为 nickname
,当用户在此input进行输入时,键盘上方会展示微信昵称。
代码示例
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
<image class="avatar" src="{{avatarUrl}}"></image>
</button>
<input type="nickname" class="weui-input" placeholder="请输入昵称"/>
用户隐私协议
这里需要注意的是,收集用户信息需要添加用户协议、个人信息保护政策,不添加的话会被打回。
还需要去小程序后台设置 用户隐私保护指引,不设置也会被打回。
uniapp双向绑定问题
我用的是uni-preset-vue-vite-ts模板进行开发,按文档看,小程序是支持模板指令v-model的,但在实际开发中并不生效,经过测试只能是:value+@input方式实现。
<input" :value="formData.nickName" @input="handleChangeNickName" placeholder="请输入">
...
const handleChangeNickName = (event) => {
formData.nickName = event.detail.value
}
昵称填写
这里需要注意的是,如果input类型是nickname,点击微信昵称,并不能触发@input方法,需要额外监听@change方法
<input type="nickname" class="nickname" :value="formData.nickName" @input="handleChangeNickName" @change="handleChangeNickName" placeholder="请输入">
...
const handleChangeNickName = (event) => {
formData.nickName = event.detail.value
}
引入vant-weapp
一开始我是按照vant官网去搞的,但它好像没有根据开发者工具更新去更新,导致我也是在不断尝试踩坑,最终也没按照它的流程搞定:
我是倒在了npm构建报错,错误离奇的很,也根据社区提供的解决办法搞了,不知道是不是版本问题,卒,放弃该方案
全局引入
chatgpt给出的全局引入方案(看了下也是google高搜索答案)
在src目录下创建wxcomponents文件夹
把我们下好的文件vant-weapp里面只留下dist其余的可以全部删掉,然后把vant-weapp放到 wxcomponents里面
全局引入
// /src/pages.json { ... "globalStyle": { "navigationBarTextStyle": "black", "navigationBarBackgroundColor": "#F8F8F8", "backgroundColor": "#F8F8F8", "usingComponents": { "van-button": "wxcomponents/vant/button", "van-card": "wxcomponents/vant/card", "van-cell": "wxcomponents/vant/cell", "van-cell-group": "wxcomponents/vant/cell-group", "van-checkbox": "wxcomponents/vant/checkbox", "van-checkbox-group": "wxcomponents/vant/checkbox-group", "van-col": "wxcomponents/vant/col", "van-dialog": "wxcomponents/vant/dialog", "van-field": "wxcomponents/vant/field", "van-goods-action": "wxcomponents/vant/goods-action", "van-goods-action-icon": "wxcomponents/vant/goods-action-icon", "van-goods-action-button": "wxcomponents/vant/goods-action-button", "van-icon": "wxcomponents/vant/icon", "van-loading": "wxcomponents/vant/loading", "van-nav-bar": "wxcomponents/vant/nav-bar", "van-notice-bar": "wxcomponents/vant/notice-bar", "van-notify": "wxcomponents/vant/notify", "van-panel": "wxcomponents/vant/panel", "van-popup": "wxcomponents/vant/popup", "van-progress": "wxcomponents/vant/progress", "van-radio": "wxcomponents/vant/radio", "van-radio-group": "wxcomponents/vant/radio-group", "van-row": "wxcomponents/vant/row", "van-search": "wxcomponents/vant/search", "van-slider": "wxcomponents/vant/slider", "van-stepper": "wxcomponents/vant/stepper", "van-steps": "wxcomponents/vant/steps", "van-submit-bar": "wxcomponents/vant/submit-bar", "van-swipe-cell": "wxcomponents/vant/swipe-cell", "van-switch": "wxcomponents/vant/switch", "van-tab": "wxcomponents/vant/tab", "van-tabs": "wxcomponents/vant/tabs", "van-tabbar": "wxcomponents/vant/tabbar", "van-tabbar-item": "wxcomponents/vant/tabbar-item", "van-tag": "wxcomponents/vant/tag", "van-toast": "wxcomponents/vant/toast", "van-transition": "wxcomponents/vant/transition", "van-tree-select": "wxcomponents/vant/tree-select", "van-datetime-picker": "wxcomponents/vant/datetime-picker", "van-rate": "wxcomponents/vant/rate", "van-collapse": "wxcomponents/vant/collapse", "van-collapse-item": "wxcomponents/vant/collapse-item", "van-picker": "wxcomponents/vant/picker", "van-date-picker": "wxcomponents/vant/datetime-picker", "van-uploader": "wxcomponents/vant/uploader", "van-empty": "wxcomponents/vant/empty", "van-grid": "wxcomponents/vant/grid", "van-grid-item": "wxcomponents/vant/grid-item" } } ... }
全局分享
创建一个share.ts文件
import {imageApi} from '@/utils/env'
export default {
onShareAppMessage() {
return {
title: 'xxx',
path: '/pages/index/index',
imageUrl: `${imageApi}/images/share.png`
};
},
onShareTimeline() {
return {
title: 'xxx',
path: '/pages/index/index',
imageUrl: `${imageApi}/images/share.png`
};
}
}
然后在src/main.ts引入,这样就可以做到每个页面都可以分享了
import { createSSRApp } from "vue";
import App from "./App.vue";
import * as Pinia from 'pinia';
import share from './utils/share' //分享设置
// import "@/assets/base.css"
export function createApp() {
const app = createSSRApp(App);
app.use(Pinia.createPinia());
app.mixin(share)
return {
app,
Pinia,
};
}
自定义tabbar
在src目录下创建custom-tab-bar目录
// index.vue <script setup lang="ts"> import {ref} from 'vue' const props = defineProps({ active: { type: Number, required: true } }); const active = ref(props.active) const list = [ { "pagePath": "/pages/index/index", "text": "首页" }, { "pagePath": "/pages/appointment/index", "text": "预约" }, { "pagePath": "/pages/upload/index", "text": "上传小票" }, { "pagePath": "/pages/user/index", "text": "我的" } ] const onChange = (event: { detail: number; }) => { uni.switchTab({ url: list[event.detail].pagePath }) } </script> <template> <van-tabbar :active="active" @change="onChange"> <van-tabbar-item icon="home-o">首页</van-tabbar-item> <van-tabbar-item icon="underway-o">预约</van-tabbar-item> <van-tabbar-item icon="plus">上传小票</van-tabbar-item> <van-tabbar-item icon="user-o">我的</van-tabbar-item> </van-tabbar> </template> <style scoped lang="scss"> </style>
在pages.json把tabBar设置为自定义,这里的list必须要定义,否者会报错
{ ... "tabBar": { "custom": true, "list": [{ "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/appointment/index", "text": "预约" }, { "pagePath": "pages/upload/index", "text": "上传小票" }, { "pagePath": "pages/user/index", "text": "我的" }] }, ... }
需要在list的页面中引入该tabbar生效