uniapp+vant-weapp 开发小程序踩坑实录

Aditya2024-12-25小程序Uni-appVue

引子

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 时后(以下统称 “生效期” ),用户头像昵称获取规则将进行如下调整:

  1. 自生效期起,小程序 wx.getUserProfile 接口将被收回:生效期后发布的小程序新版本,通过 wx.getUserProfile 接口获取用户头像将统一返回默认灰色头像open in new window,昵称将统一返回 “微信用户”。生效期前发布的小程序版本不受影响,但如果要进行版本更新则需要进行适配。
  2. 自生效期起,插件通过 wx.getUserInfo 接口获取用户昵称头像将被收回:生效期后发布的插件新版本,通过 wx.getUserInfo 接口获取用户头像将统一返回默认灰色头像open in new window,昵称将统一返回 “微信用户”。生效期前发布的插件版本不受影响,但如果要进行版本更新则需要进行适配。通过 wx.login 与 wx.getUserInfo 接口获取 openId、unionId 能力不受影响。
  3. 「头像昵称填写能力」支持获取用户头像昵称:如业务需获取用户头像昵称,可以使用「头像昵称填写能力open in new window」(基础库 2.21.2 版本开始支持,覆盖iOS与安卓微信 8.0.16 以上版本),具体实践可见下方《最佳实践》。

小程序用户头像昵称获取规则调整公告open in new window

原先用getUserInfo、getUserProfile获取用户信息的方式都废弃了,即使加密信息解密也都是微信用户、灰色头像(别问,问就是全踩了一次,我不理解都废弃了还放在开发文档干啥)。目前只能通过用户手动填写收集用户信息。

头像选择

需要将 buttonopen in new window 组件 open-type 的值设置为 chooseAvatar,当用户选择需要使用的头像之后,可以通过 bindchooseavatar 事件回调获取到头像信息的临时路径。

昵称填写

需要将 inputopen in new window 组件 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="请输入昵称"/>

用户隐私协议

这里需要注意的是,收集用户信息需要添加用户协议、个人信息保护政策,不添加的话会被打回

还需要去小程序后台设置 用户隐私保护指引,不设置也会被打回。

用户隐私保护指引填写说明open in new window

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官网去搞的,但它好像没有根据开发者工具更新去更新,导致我也是在不断尝试踩坑,最终也没按照它的流程搞定:

vant-wepp 快速上手open in new window

我是倒在了npm构建报错,错误离奇的很,也根据社区提供的解决办法搞了,不知道是不是版本问题,卒,放弃该方案

全局引入

chatgpt给出的全局引入方案(看了下也是google高搜索答案)

  1. 在src目录下创建wxcomponents文件夹

  2. 下载最新的https://github.com/youzan/vant-weappopen in new window

  3. 把我们下好的文件vant-weapp里面只留下dist其余的可以全部删掉,然后把vant-weapp放到 wxcomponents里面

  4. 全局引入

    // /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

  1. 在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>
    
  2. 在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": "我的"
    		}]
    	},
    ...
    }
    
  3. 需要在list的页面中引入该tabbar生效

Last Updated 2024/12/27 11:36:49