一、简单说说准备工作:

创立项目

  • 东西: HBuilder最新稳定版, uni-app官网可下载
  • 菜单栏:文件-> 新建 -> 项目,创立一个空白的根据vue3版别的模板目录即可
    uni-app+vue3+vant开发微信小程序探路...

调试

  • 东西:预先下载安装 微信开发者东西
  • HBuilder中选中当前项目的任何一个文件
  • uni-app+vue3+vant开发微信小程序探路...
  • 菜单栏:运转-> 运转到小程序模拟器 ->微信开发者东西
  • 运转成功会主动发动微信开发者东西,等候编译完成会看到测验界面
  • uni-app+vue3+vant开发微信小程序探路...

【坑】开发方式进行真机调试会白屏,需求在发行方式下进行真机调试

【坑】如呈现微信开发者东西console里边爆红,能够试试点一下微信开发者东西上方菜单里边的从头编译,说不定就好了(* ̄︶ ̄)

发布

  • 菜单栏:发行-> 小程序-微信
  • 此时需求一个小程序AppId,需在微信公众平台上开通

二、一些技巧和坑

1.引证vant组件

引进组件目录

  1. /pages 同级创立 /wxcomponents/vant 目录
  2. 下载微信小程序版别的vant代码
  3. 解压代码,把/dist目录内的文件复制进去新建的/wxcomponents/vant目录中
  4. 开发进程中应参阅对应版别的文档:vant-contrib.gitee.io/vant-weapp 但需求把对应的引证语法改成vue的语法,如:
<van-cell-group>
    <van-field value="{{ value }}" placeholder="请输入用户名" border="{{ false }}"
    bind:change="onChange" />
</van-cell-group>

改为:

<van-cell-group>
    <van-field :value="value" placeholder="请输入用户名" :border="false"
    @change="onChange" />
</van-cell-group>

引证

修正pages.json文件

大局引证

"globalStyle":{} 属性下参加以下片段,可按需引进具体需求大局引进的组件,引进规矩如下:

"usingComponents": {
   "van-cell-group": "/wxcomponents/vant/cell-group/index",
   "van-field": "/wxcomponents/vant/field/index",
   //...
}

uni-app+vue3+vant开发微信小程序探路...

单页引证

把上述的代码放在对应的页面装备内,如:

uni-app+vue3+vant开发微信小程序探路...

【坑】报错??

页面【wxcomponents/vant/info/index]过错:
 Error: module 'wxcomponents/vant/info/index.js' is not defined,
 require args is 'wxcomponents/vant/info/index.js'

uni-app+vue3+vant开发微信小程序探路...

WAServiceMainContext.js?t=wechat&s=1666746784000&v=2.27.0:1 SyntaxError:
Cannot use import statement outside a module(env: Windows,mp,1.06.2209190; lib: 2.27.0)

uni-app+vue3+vant开发微信小程序探路...

【填坑】

这是由于微信开发者东西没有启用ES6转ES5功用而报错

微信开发者东西右上角:详情-> 本地设置 -> 勾选“将JS编译成ES5”即可

uni-app+vue3+vant开发微信小程序探路...

但或许从头编译或热重载后,该选项“将JS编译成ES5”又不勾选了,此时能够直接去修正项目文件manifest.json, 勾选微信小程序装备-> ES6转ES5 即可

uni-app+vue3+vant开发微信小程序探路...

如翻开的是manifest.json的源码,能够在对应的方位增加以下装备:

uni-app+vue3+vant开发微信小程序探路...

【坑】引证van-toast组件无效或报错

1.未找到van-toast 节点,请承认 selector 及 context 是否正确

组件内引证牢记参阅官方文档,需求给页面引进一个van-toast组件,才能在script内运用 Toast() 的办法

<van-toast id="van-toast" />

留意:只需或许会调用Toast()的界面,都需求刺进该组件

2.在非组件的js文件中引证Toast(),正常运用或许会像如下的方式:

uni-app+vue3+vant开发微信小程序探路...

开发方式下是能够正常调用,可是在发行方式下,会报错

vendor.js? [sm]:1 TypeError: s.Toast is not a function

uni-app+vue3+vant开发微信小程序探路...

TypeError: Cannot read property 'success' of undefined

uni-app+vue3+vant开发微信小程序探路...

假如把Toast打印出来,会发现为null, 原因是Toast并未正常引进

理由揭秘:

翻开/wxcomponents/vant/toast/toast.js,你会发现,最终一句代码为:

export default Toast;

开发方式下,初度编译,在微信开发者东西翻开这个文件,发现这句话没有变,编译进程并没有把它进行处理

而当回去修正了一下代码,热重载后,这句话就变成了:

exports.Toast = Toast;

估量就是微信开发者东西进行了再次编译,把一些组件目录的代码进行转换了,而uni-app没有对这些代码进行处理

发布方式下,不存在热重载,在微信开发者东西翻开这个文件,就会发现它一直是

export default Toast;

而编译后引证这个文件的代码始终是一样的:

uni-app+vue3+vant开发微信小程序探路...

都是经过[module].Toast()来进行引证。

这就会导致一个问题,咱们什么都不改直接引证的话,会呈现热重载后是能正常,初始加载和发布都不能正常运用,由于 exports.Toastexport default Toast咱们引进后的内容是不一样的

具体原理可参阅这个地址

【填坑】

/wxcomponents/vant/toast/toast.js的最终一句导出句子修正为:

exports.Toast = Toast;

引进句子修正为:

const Toast = require('../wxcomponents/vant/toast/toast.js').Toast
export function loadInfo() {
	Toast('加载成功')
}

大功告成!

2.自定义顶部导航栏,以便于修正顶栏款式(复原UI规划图;加布景图、Logo之类..)

修正pages.json文件

{
    ...,
    "globalStyle": {
        "navigationStyle": "custom",
        ...
     }
}

创立对应的自定义组件: components/commonHeader/commonHeader.vue, 在界面中引进即可(可按下方第4点的方式进行按需引进的设置)

私家tips

获取系统状况栏和菜单高度,用于设置自定义顶部导航栏的高度

修正App.vue文件

onLaunch: function() {
    console.log('App Launch')
    uni.getSystemInfo({
        success: function(e) {
            // #ifdef MP-WEIXIN
            uni.$StatusBarHeight = e.statusBarHeight;
            // getMenuButtonBoundingClientRect 用于获取页面右上角圆角按钮的方位信息
            let custom = wx.getMenuButtonBoundingClientRect();
            uni.$CustomBarHeight = custom.bottom - e.statusBarHeight + 8
            // #endif
            //uni 为大局目标,能够挂载大局参数,在其他组件能够直接运用
        }
    })
}

私家tips2: 监听页面翻翻滚态修正顶部导航栏款式

场景:可用于全屏布景图,翻滚后需求修正顶部导航栏的布景和文字颜色的场景

// page代码
onPageScroll(e) {
        const { scrollTop } = e
        // pageTop 可指定翻滚高度
        const pageTop = 100
        if (scrollTop > pageTop) {
                // headerBg, headerColor 能够是自定义导航栏的一些props, 按需运用
                this.headerBg = '#fff'
                this.headerColor = 'black'
                // 修正状况栏款式(顶部的时间日期等内容)
                uni.setNavigationBarColor({
                        frontColor: '#000000',
                        backgroundColor: '' // 必填项,不能不传,但能够为空字符串
                })
        } else {
                this.headerBg = 'transparent'
                this.headerColor = 'white'
                uni.setNavigationBarColor({
                        frontColor: '#ffffff',
                        backgroundColor: ''
                })
        }
}

3.自定义底部菜单栏tabbar

修正pages.json文件

{
    ...,
    "tabBar": {
        "custom": true,
        "list": [{
                        "pagePath": "pages/index/index",
                        "text": "主页"
                },
                {
                        "pagePath": "pages/passed/index",
                        "text": "主页面1"
                },
                {
                        "pagePath": "pages/my/index",
                        "text": "个人中心"
                },
                ...
        ]
    }
}

创立对应的自定义组件: components/commonTabbar/commonTabbar.vue, 在对应主界面中引进即可,能够运用vanttabbar组件,可参阅如下:

<template>
    <van-tabbar :active="active" active-color="#00C84A" inactive-color="#CDCDCD" :border="false" @change="onChange">
        <van-tabbar-item v-for="item in tabs" :key="item.name">
                <image slot="icon" :src="item.iconNormal" mode="contain" style="width: 48rpx; height: 48rpx;" />
                <image slot="icon-active" :src="item.iconActive" mode="contain" style="width: 48rpx; height: 48rpx;" />
                {{item.name}}
        </van-tabbar-item>
    </van-tabbar>
</template>
<script>
export default {
    props: {
        current: {
            type: Number,
            default: 1
        }
    },
    data() {
        return {
           active: 1,
           tabs: [{
                    name: '主页面1',
                    iconNormal: '/static/passed.png',
                    iconActive: '/static/passed-active.png',
                    path: '/pages/passed/index'
                },
                {
                    name: '主页',
                    iconNormal: '/static/index.png',
                    iconActive: '/static/index-active.png',
                    path: '/pages/index/index'
                },
                {
                    name: '个人中心',
                    iconNormal: '/static/my.png',
                    iconActive: '/static/my-active.png',
                    path: '/pages/my/index'
                }
            ]
        }
    },
    watch: {
        current: {
            immediate: true,
            handler: function(val) {
                    this.active = val
            }
        }
    },
    methods: {
        onChange(e) {
            const current = e.detail
            uni.switchTab({
                    url: this.paths[current]
            })
        }
    }
}

私家tips

为了使界面主要内容不受tabbar覆盖,能够在van-tabbar组件前面参加一个空节点,如下:

    <view class="footer-empty">&nbsp;</view>
    //css 款式
     .footer-empty {
	height: 100rpx;
	padding-bottom: env(safe-area-inset-bottom);
    }

4.运用easycom主动按需加载自定义组件(为什么我的组件总是无法主动识别?)

修正pages.json文件

{
    ...,
    "easycom": {
            "autoscan": true,
            "custom": {
                "^uni-(.*)": "@/components/uni-$1.vue", // 匹配components目录内的vue文件
                "^vue-file-(.*)": "packageName/path/to/vue-file-$1.vue" // 匹配node_modules内的vue文件
            }
    }
}

只需敞开了autoscan, 会主动扫描目录规矩契合/components/组件称号/组件称号.vue的所有文件,主动进行引进,无需再在custom中引进

引进后page中直接运用组件即可

留意:假如新建的组件引证无效,在HBuilder中从头编译项目试试

5.引证富文本显示和编辑组件mp-html

官方文档

mp-html 默许只要显示富文本功用,需求支撑编辑状况的话,要额外代码, 参阅 editable方式设置文档 小程序示例代码

其实引证组件不费事,参照demo,能够按照自己的需求修正菜单icon之类的,比较便利

6.运用微信原生小程序提供的wxml-to-canvas进行动态海报生成以及保存到本地

官方文档

为了便利改造,不采用npm的办法进行安装,直接翻开代码片段

uni-app+vue3+vant开发微信小程序探路...

在代码片段中对应的两个目录,复制到自己的项目中/wxcomponents目录下

uni-app+vue3+vant开发微信小程序探路...

改造目的和内容:

1.wxml-to-canvas一般用于生成海报,而海报又一般经过popup的方式弹出,所以需求改造烘托时机,等popup弹出后再烘托

默许引证即烘托,可是canvas没法在一个躲藏节点中烘托,所以把默许的烘托时机改为手动(经过自定义代码调用烘托)

修正wxml-to-canvas/index.js文件

  • 在methods中新增一个办法:
methods: {
    initCanvas() {
        ...
    }
}
  • attached中的烘托代码剪切进去

uni-app+vue3+vant开发微信小程序探路...

  • canvas需求先初始化,初始化完毕后再调用renderToCanvas进行制作, 否则会报错 网上许多方案都是用setTimeout来进行延迟调用, 可是我觉得这是不稳妥的, 延迟时间设长了设短了都不好, 所以我把initCanvas写成一个异步函数,如下:
methods: {
    initCanvas() {
        return new Promise((resolve,reject) => {
            const dpr = wx.getSystemInfoSync().pixelRatio
            const query = this.createSelectorQuery()
            this.dpr = dpr
            query.select('#canvas')
              .fields({node: true, size: true})
              .exec(res => {
                const canvas = res[0].node
                const ctx = canvas.getContext('2d')
                canvas.width = res[0].width * dpr
		canvas.height = res[0].height * dpr
                ctx.scale(dpr, dpr)
                this.ctx = ctx
                this.canvas = canvas
                resolve(canvas)
             })
        })
    },
    ...
},
  • 页面代码中:

刺进组件

<van-popup :show="showPopup" :close-on-click-overlay="true" custom-style="background:transparent" @close="showPopup = false" @after-enter="opened">
    <view>
      <wxml-to-canvas ref="widget" class="widget"></wxml-to-canvas>
    </view>
</van-popup>

在popup弹出后,调用办法

methods: {
    async opened() {
        const canvas = await this.$refs.widget.initCanvas()
        Toast.loading({
            message: '加载中',
            forbidClick: true
        });
        const obj = { wxml: '...', styles: '...'}
        this.$refs.widget.renderToCanvas(obj).then(res => {
            Toast.clear()
        })
    }
}

2.canvas自适应宽高改造:

  • 获取实践屏幕宽度和规划稿的比例,核算每个元素的实践尺寸和边距等

  • 修正wxml-to-canvas/index.js文件

    • 修正attached()办法
    attached() {
        const sys = wx.getSystemInfoSync();
        //拿到设备的宽度,跟规划图宽度的比例
        const screenRatio = sys.screenWidth / 375;
        this.setData({
                screenRatio,
                width: this.data.width * screenRatio,
                height: this.data.height * screenRatio,
        });
    }
    
    • 修正initCanvas()办法
    initCanvas() {
        // ...省掉
        // canvas.width = res[0].width * dpr
        // canvas.height = res[0].height * dpr
        canvas.width = this.data.width * dpr;
        canvas.height = this.data.height * dpr;
        // ...省掉
    }
    
    • 修正renderToCanvas()办法
    renderToCanvas() {
        // const {wxml, style} = args
        const { wxml, fnGetStyle } = args
         // 经过fnGetStyle办法传入屏幕与规划稿的比例,用以核算款式
        const style = fnGetStyle(this.data.screenRatio)
        // ...省掉
    }
    
  • 可新建一个文件进行canvas节点和款式的装备, 如canvasConfig.js:

// canvasConfig.js
// function 方式便于传入动态数据
export default function(info) {
    const wxml = `<view class="container">
        <view class="absolute mainBox"></view>
    </view>`
    const fnGetStyle = (screenRatio) => {
        return {
            // 编写款式, 称号需以驼峰命名
            absolute: {
               position: 'absolute'
            },
            container: {
                width: 300*screenRatio, //经过乘以倍率,核算出在当前屏幕分辨率下的实践宽度, 其他尺寸同理
                height: 471*screenRatio,
                position: 'relative'
            },
            mainBox: {
                width: 200*screenRatio,
                padding: 10*screenRatio,
                margin: 10*screenRatio,
                color: '#eeeeee'
            }
        }
    }
    return {
        wxml,
        fnGetStyle
    }
}
  • 修正页面中的组件调用办法:
import canvasConfig from './canvasConfig.js'
// ...省掉
methods: {
    opened() {
        ...
        const info = { title: '标题' }
        const obj = canvasConfig(info)
        this.$refs.widget.renderToCanvas(obj).then(res => {
           Toast.clear()
        })
    }
}

生成图片并保存到本地

页面代码中:

methods: {
  //...
  extraImage() {
    this.$refs.widget.canvasToTempFilePath().then(res => {
        this.saveImg(res.tempFilePath)
    })
  }, 
  async saveImg (tempFilePath) {
    const _this = this
    uni.saveImageToPhotosAlbum({
        filePath: tempFilePath,
        success: async (res) => {
            uni.showModal({
                content: '图片已保存,共享给老友吧!',
                showCancel: false,
                confirmText: '好的',
                confirmColor: '#333',
                success: function (res) {
                    // ...
                },
                fail: function (res) {
                   // ...
                }
            });
        },
        fail: function (res) {
            Toast.fail('您取消了授权')
        }
    });
  }
}

【坑】明明添加了内容,页面却还是空白

  • wxml及款式的编写需求严厉遵从运用规矩,有些固定的要求及支撑的款式,不遵从的话或许会导致烘托不出来

【坑】真机调试报错 fail canvas has not been created

  • 按照上述的办法应该不会报这个问题
  • 还报的话,查看是否canvas内的元素的烘托尺寸超出了canvas的实践宽高,超出则或许烘托失败

这次共享这么多,谢谢观看!

uni-app+vue3+vant开发微信小程序探路...

仍有无法处理的问题欢迎交流!

ps: 为了图快,本项目其实并没有用到vue3的一些新特性(懒得查文档), 就这么凑合吧哈哈