HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

npm i cheerio之后,在本地运行云函数ok,云上执行失败

问题根因:
应该在这个云函数的目录下面执行:npm init -y 和 npm i cheerio

还原我出错的原因是在项目的根目录下面执行了这两行,结果本地执行可以执行,但是云函数的package.json中间没有创建依赖信息,导致的问题。

问题根因:
应该在这个云函数的目录下面执行:npm init -y 和 npm i cheerio

还原我出错的原因是在项目的根目录下面执行了这两行,结果本地执行可以执行,但是云函数的package.json中间没有创建依赖信息,导致的问题。

unicloud云函数抖音小程序订单推送示例

uniCloud
'use strict';  
const appid = ''  
const secret = ''  
const Commodity_figure =""//商品图链接  
exports.main = async (event, context) => {  

//获取token  
    const URL1 = `https://developer.toutiao.com/api/apps/v2/token`  

    let res_ = await uniCloud.httpclient.request(URL1, {  
        method: 'POST',  
        dataType: 'json',  
        contentType: 'json', // 指定以application/json发送data内的数据  
        headers: {  
            "Content-Type": "application/json"  
        },  
        data: {  
            "appid": appid,  
            "secret": secret,  
            "grant_type": "client_credential"  
        },  

    })  

    const URL = `https://developer.toutiao.com/api/apps/order/v2/push`  

    let res_1 = await uniCloud.httpclient.request(URL, {  
        method: 'POST',  
        dataType: 'json',  
        contentType: 'json', // 指定以application/json发送data内的数据  
        headers: {  
            "Content-Type": "application/json"  
        },  
        data: {  
            "access_token": res_.data.data.access_token, // string类型,必传字段  
            "app_name": "douyin",  
            "open_id": event.open_id, // 小程序open id  
            "update_time": Number(new Date()), // 订单信息变更时间,13位毫秒级时间戳  
            "order_type": 0, // 订单类型  
            "order_status": event.order_status, //当order_type为0(普通小程序订单,非poi订单)时,请关注,必传  
            "order_detail": JSON.stringify({  
                "order_id": event.order_id, //开发者侧业务单号  
                "create_time": Number(new Date()), //订单创建的时间  
                "status": event.pay_status, //订单状态,待支付\已支付\已取消\已超时\已核销\退款中\已退款\退款失败  
                "amount": 1, //订单商品总数  
                "total_price": event.itemdata.total_amount, //订单金额  
                "detail_url": "page/user/user", //跳转小程序路径  
                "item_list": [{//商品数据  
                    "item_code": event.order_id,  
                    "img": Commodity_figure,  
                    "title": event.itemdata.subject,  
                    "sub_title": event.itemdata.body_,  
                    "amount": 1,  
                    "price": event.itemdata.total_amount,  

                }]  
            })  

        }  

    })  

    //返回数据给客户端  
    return res_1  
};  

写小程序订单推送时被抖音开发者文档里的数据结构卡了一会,把代码贴出来希望能帮到遇到这个问题的朋友

4年uniapp+unicloud开发经验,有需要前端开发、NVUE安卓、ios、或者小程序开发的老板可以联系我Q:431244025

继续阅读 »
'use strict';  
const appid = ''  
const secret = ''  
const Commodity_figure =""//商品图链接  
exports.main = async (event, context) => {  

//获取token  
    const URL1 = `https://developer.toutiao.com/api/apps/v2/token`  

    let res_ = await uniCloud.httpclient.request(URL1, {  
        method: 'POST',  
        dataType: 'json',  
        contentType: 'json', // 指定以application/json发送data内的数据  
        headers: {  
            "Content-Type": "application/json"  
        },  
        data: {  
            "appid": appid,  
            "secret": secret,  
            "grant_type": "client_credential"  
        },  

    })  

    const URL = `https://developer.toutiao.com/api/apps/order/v2/push`  

    let res_1 = await uniCloud.httpclient.request(URL, {  
        method: 'POST',  
        dataType: 'json',  
        contentType: 'json', // 指定以application/json发送data内的数据  
        headers: {  
            "Content-Type": "application/json"  
        },  
        data: {  
            "access_token": res_.data.data.access_token, // string类型,必传字段  
            "app_name": "douyin",  
            "open_id": event.open_id, // 小程序open id  
            "update_time": Number(new Date()), // 订单信息变更时间,13位毫秒级时间戳  
            "order_type": 0, // 订单类型  
            "order_status": event.order_status, //当order_type为0(普通小程序订单,非poi订单)时,请关注,必传  
            "order_detail": JSON.stringify({  
                "order_id": event.order_id, //开发者侧业务单号  
                "create_time": Number(new Date()), //订单创建的时间  
                "status": event.pay_status, //订单状态,待支付\已支付\已取消\已超时\已核销\退款中\已退款\退款失败  
                "amount": 1, //订单商品总数  
                "total_price": event.itemdata.total_amount, //订单金额  
                "detail_url": "page/user/user", //跳转小程序路径  
                "item_list": [{//商品数据  
                    "item_code": event.order_id,  
                    "img": Commodity_figure,  
                    "title": event.itemdata.subject,  
                    "sub_title": event.itemdata.body_,  
                    "amount": 1,  
                    "price": event.itemdata.total_amount,  

                }]  
            })  

        }  

    })  

    //返回数据给客户端  
    return res_1  
};  

写小程序订单推送时被抖音开发者文档里的数据结构卡了一会,把代码贴出来希望能帮到遇到这个问题的朋友

4年uniapp+unicloud开发经验,有需要前端开发、NVUE安卓、ios、或者小程序开发的老板可以联系我Q:431244025

收起阅读 »

还没尝试过ChatGPT的小伙伴, 可以尝试一下, 直接在公众号里提问。

ChatGPT

使用的模型是 gpt-3.5-turbo-0301 不是最新的4.0(成本太高) 不过在大部分场景也是够用的。

扫码关注公众号

如果二维码失效就 手动搜索 【可知消息推送平台】

继续阅读 »

使用的模型是 gpt-3.5-turbo-0301 不是最新的4.0(成本太高) 不过在大部分场景也是够用的。

扫码关注公众号

如果二维码失效就 手动搜索 【可知消息推送平台】

收起阅读 »

iconfont-tools转彩色图标后重复排列问题

正常使用iconfont-tools将阿里图标库转为彩色图标。
如果图标不是正方形,那么就会出现重复问题
比如这样


在对应的引入css文件内加入 !important 即可,图片上有标注

继续阅读 »

正常使用iconfont-tools将阿里图标库转为彩色图标。
如果图标不是正方形,那么就会出现重复问题
比如这样


在对应的引入css文件内加入 !important 即可,图片上有标注

收起阅读 »

uniapp全局弹窗的封装实现

需求

平时主要是用uni.showModal 实现弹窗效果,但是各平台app和h5样式都不一样,ui给了统一的弹窗样式。
为了兼容app和h5,实现跟uni.showModal一样简单使用就能触发弹窗,且可扩展,兼容样式,按钮修改,弹窗内容富文本展示等,决定自己封装一个全局弹窗

实现

我们知道,app里面如果用普通view自定义弹窗,无法覆盖导航栏和底部tab栏
解决办法:
1、可以使用subnvue webview子窗体
2、使用 plus.nativeObj.View
3、参考插件市场里的解决方案,新建一个页面进行跳转,可以实现伪弹窗(其实是打开一个背景透明的页面)

第一个方案,需要在每个页面(page.json)里配置subNVues ,麻烦且违背了全局的概念。第二个编写复杂,且页面样式较难自定义,最后选择了第三个方案
需求,能够接收外部参数(props)。关于外部参数这里,我使用了vuex,定于全局变量然后传入组件

实施过程

1、定义props类型

 popupConfig:  
    {  
        type: 1, // 弹窗类型(1、提交反馈弹窗 2、modal弹窗 3、自定义弹窗(设为此后下面其他参数将无效))  
    showCancel: false, // 是否显示取消按钮  
    confirmText:'确定', // 确定按钮文字  
    cancelText:'取消', // 取消按钮文字  
    closeOpacity:false,// 点击遮罩是否关闭弹窗  
        title: '', // 标题  
        content: '' ,// 内容文本  
    icon: 1// 反馈弹窗状态 (1、成功 2、失败 3、正常)  
    },

2、编写弹窗组件和方法
这里因为是用的页面跳转方法,那实际应该是个页面
pages.json里注册好

{  
        "path": "pages/globalPopup/globalPopup",  
        "style": {  
            "navigationStyle": "custom",  
            "backgroundColor": "transparent",  
            "app-plus": {  
                "animationType": "fade-in",  
                "background": "transparent",  
                "popGesture": "none",  
                "bounce": "none",  
                "titleNView": false  
            }  
        }  
},

弹窗显示就是跳转页面uni.navigateTo,隐藏就是返回uni.navigateBack,这里展示一部分,具体代码可查看附件里的源码

<!-- 成功或失败弹窗 -->  
            <template v-if="params.type === 1">  
                <view class="popup-box">  
                    <template v-if="params.icon === 1">  
                        <image class="icon-img" style="width:210rpx;" src="/static/image/popup_success.png" mode="widthFix"></image>  
                    </template>  
                    <template v-else-if="params.icon === 2">  
                        <image class="icon-img" style="width:120rpx;" src="/static/image/popup_fail.png" mode="widthFix"></image>  
                    </template>  
                    <template v-else-if="params.icon === 3">  
                        <image class="icon-img" style="width:120rpx;" src="/static/image/popup_info.png" mode="widthFix"></image>  
                    </template>  
                    <view class="title">  
                        <text>{{params.title}}</text>  
                    </view>  
                    <view class="content">  
                        <text>{{params.content}}</text>  
                    </view>  
                    <view class="btn-box" style="margin-top: 30rpx;">  
                        <template v-if="params.showCancel">  
                            <button class="btn btn-two" :style="`border:1rpx solid;color:${primaryColor};`" @click="cancel">{{params.cancelText}}</button>  
                            <button class="btn btn-two" :style="`color:#fff;background:${primaryColor};`" @click="confirm">{{params.confirmText}}</button>  
                        </template>  
                        <template v-else>  
                            <button class="btn btn-one" @click="confirm">{{params.confirmText}}</button>  
                        </template>  
                    </view>  
                </view>  
            </template>  
            <!-- modal弹窗 -->  
            <template v-else-if="params.type === 2">  
                <view class="modal-box">  
                    <view class="modal-top">  
                        <text class="modal-title">{{params.title}}</text>  
                        <text class="modal-content">{{params.content}}</text>  
                    </view>  
                    <view class="modal-btn">  
                        <template v-if="params.showCancel">  
                            <view class="item" @click="cancel">{{params.cancelText}}</view>  
                            <u-line direction="col" color="#eee" />  
                            <view class="item active" @click="confirm">{{params.confirmText}}</view>  
                        </template>  
                        <template v-else>  
                            <view class="item active" style="width: 500rpx;" @click="confirm">{{params.confirmText}}</view>  
                        </template>  
                    </view>  
                </view>  
            </template>  
            <!-- 自定义弹窗 -->  
            <template v-else-if="params.type === 3">  
                <view class="rich-box">  
                    <rich-text :nodes="params.content"></rich-text>  
                </view>  
            </template>

关键点在于逻辑,因为要使用诸如uni.showModel 这样的api来实现弹窗效果,需要进行api封装, 添加显示 show() 隐藏 hide() 的方法,另外需要将点击按钮后的回调传给api,使用了uni.navigateTo 的事件发送。页面跳转的方式不适用于h5,所以h5的需要单独处理(h5的弹窗其实是一个dom节点。使用dom操作),弹窗展示后需要重置数据,不然下个弹窗会出现上个弹窗的信息

import Vue from 'vue';  
import globalPopup from './globalPopup.vue'  

class GlobalPopup {  
    constructor () {  
        const PopupVue = Vue.extend(globalPopup);  
        this.popupDom = new PopupVue()  
    }  
       // 弹窗成功后需要重置popupConfig数据  
    init(){  
        const config = {  
            type: 1, // 弹窗类型(1、提交反馈弹窗 2、modal弹窗 3、自定义弹窗(设为此后其他参数无效))  
            showCancel: false, // 是否显示取消按钮  
            confirmText:'确定', // 确定按钮文字  
            cancelText:'取消', // 取消按钮文字  
            closeOpacity:false,// 点击遮罩是否关闭弹窗  
            title: '', // 标题  
            content: '' ,// 内容文本  
            icon: 1// 反馈弹窗状态 (1、成功 2、失败 3、正常)  
        }  
        Vue.prototype.$store.dispatch('updatePopupConfig',config)  
    }  
    // 显示弹窗  
    show (params) {  
        let that = this;  
        // Vue.store 传递参数  
        Vue.prototype.$store.dispatch('updatePopupConfig',params)  
        // #ifdef APP-PLUS  
            uni.navigateTo({  
                url: '/pages/globalPopup/globalPopup',  
                events:{  
                    confirm: function(data) {  
                      that.init()  
                      params.confirm && params.confirm()  
                    },  
                    cancel: function(data) {  
                      that.init()  
                      params.cancel && params.cancel()  
                    }  
                }  
            })  
        // #endif  

        // #ifdef H5  
        this.popupDom.cancel = params?.cancel || this.popupDom.cancel;  
        this.popupDom.confirm = params?.confirm || this.popupDom.confirm;  
        this.popupDom.vm = this.popupDom.$mount();  
        this.popupDom.show = true;  
        const lastEl = document.body.lastElementChild;  
        if(lastEl.id !== 'popup-box'){  
            setTimeout(()=>{  
                document.body.appendChild(that.popupDom.vm.$el)  
            })  
        }  
        // #endif  

    };  

    // 隐藏弹窗 h5弹窗调用回调后需要手动隐藏弹窗(因为无法在回调中获取对象本身,有大佬可以自行优化)  
    hide () {  
        // #ifdef H5  
        let that = this;  
        this.popupDom.show = false;  
        const lastEl = document.body.lastElementChild;  
        if(lastEl.id === 'popup-box'){  
            setTimeout(()=>{  
                document.body.removeChild(lastEl)  
                that.init()  
            },500)  
        }  
        // #endif  
    }  
}

将事件注册到全局
main.js 添加

import globalPopup from '@/pages/globalPopup/globalPopup.js'   
Vue.prototype.$popup = globalPopup;  

3、效果展示

this.$popup.show({  
    title:'提交成功',  
    content:'请等待确认',  
    confirm:()=>{  
        // #ifdef H5  
        this.$popup.hide()  
        // #endif             
    }  
})

2023-6-9 更新

一直想把小程序的全局弹窗也做了,原计划把小程序和h5封装为同一个方法,即使用vue的全局注册功能,将自定义弹窗注册为一个全局组件,但是发现小程序不像h5一样可以操作dom,即使注册了要在页面中使用还是得用标签加上,找了很多资料都没有类似js添加dom的操作,知道发现一个插件vue-inset-loader,作者使用sfc模板在编译阶段指定位置插入自定义内容,参考文档,解决了我的困扰。
但是在使用中还是发现了不少问题,如文件只能放在components文件夹中,数据传输只能用vuex,猜测可能是uni的easycom 配置影响,如果有大佬明白,还请告知一下。
还有之前一直存在的一个问题,在h5弹窗调用回调后需要手动隐藏弹窗(因为无法在回调中获取对象本身),当时自己弄了半天,结果今天意外就找到了解决办法,那就是把方法挂载到vuex中,通过跨页面调用实现回调!

已将该插件放到插件市场,需要的可以访问查看

本篇探讨一种全局弹出的封装方法,大佬们可以在此基础上优化使用,源码在附件中

继续阅读 »

需求

平时主要是用uni.showModal 实现弹窗效果,但是各平台app和h5样式都不一样,ui给了统一的弹窗样式。
为了兼容app和h5,实现跟uni.showModal一样简单使用就能触发弹窗,且可扩展,兼容样式,按钮修改,弹窗内容富文本展示等,决定自己封装一个全局弹窗

实现

我们知道,app里面如果用普通view自定义弹窗,无法覆盖导航栏和底部tab栏
解决办法:
1、可以使用subnvue webview子窗体
2、使用 plus.nativeObj.View
3、参考插件市场里的解决方案,新建一个页面进行跳转,可以实现伪弹窗(其实是打开一个背景透明的页面)

第一个方案,需要在每个页面(page.json)里配置subNVues ,麻烦且违背了全局的概念。第二个编写复杂,且页面样式较难自定义,最后选择了第三个方案
需求,能够接收外部参数(props)。关于外部参数这里,我使用了vuex,定于全局变量然后传入组件

实施过程

1、定义props类型

 popupConfig:  
    {  
        type: 1, // 弹窗类型(1、提交反馈弹窗 2、modal弹窗 3、自定义弹窗(设为此后下面其他参数将无效))  
    showCancel: false, // 是否显示取消按钮  
    confirmText:'确定', // 确定按钮文字  
    cancelText:'取消', // 取消按钮文字  
    closeOpacity:false,// 点击遮罩是否关闭弹窗  
        title: '', // 标题  
        content: '' ,// 内容文本  
    icon: 1// 反馈弹窗状态 (1、成功 2、失败 3、正常)  
    },

2、编写弹窗组件和方法
这里因为是用的页面跳转方法,那实际应该是个页面
pages.json里注册好

{  
        "path": "pages/globalPopup/globalPopup",  
        "style": {  
            "navigationStyle": "custom",  
            "backgroundColor": "transparent",  
            "app-plus": {  
                "animationType": "fade-in",  
                "background": "transparent",  
                "popGesture": "none",  
                "bounce": "none",  
                "titleNView": false  
            }  
        }  
},

弹窗显示就是跳转页面uni.navigateTo,隐藏就是返回uni.navigateBack,这里展示一部分,具体代码可查看附件里的源码

<!-- 成功或失败弹窗 -->  
            <template v-if="params.type === 1">  
                <view class="popup-box">  
                    <template v-if="params.icon === 1">  
                        <image class="icon-img" style="width:210rpx;" src="/static/image/popup_success.png" mode="widthFix"></image>  
                    </template>  
                    <template v-else-if="params.icon === 2">  
                        <image class="icon-img" style="width:120rpx;" src="/static/image/popup_fail.png" mode="widthFix"></image>  
                    </template>  
                    <template v-else-if="params.icon === 3">  
                        <image class="icon-img" style="width:120rpx;" src="/static/image/popup_info.png" mode="widthFix"></image>  
                    </template>  
                    <view class="title">  
                        <text>{{params.title}}</text>  
                    </view>  
                    <view class="content">  
                        <text>{{params.content}}</text>  
                    </view>  
                    <view class="btn-box" style="margin-top: 30rpx;">  
                        <template v-if="params.showCancel">  
                            <button class="btn btn-two" :style="`border:1rpx solid;color:${primaryColor};`" @click="cancel">{{params.cancelText}}</button>  
                            <button class="btn btn-two" :style="`color:#fff;background:${primaryColor};`" @click="confirm">{{params.confirmText}}</button>  
                        </template>  
                        <template v-else>  
                            <button class="btn btn-one" @click="confirm">{{params.confirmText}}</button>  
                        </template>  
                    </view>  
                </view>  
            </template>  
            <!-- modal弹窗 -->  
            <template v-else-if="params.type === 2">  
                <view class="modal-box">  
                    <view class="modal-top">  
                        <text class="modal-title">{{params.title}}</text>  
                        <text class="modal-content">{{params.content}}</text>  
                    </view>  
                    <view class="modal-btn">  
                        <template v-if="params.showCancel">  
                            <view class="item" @click="cancel">{{params.cancelText}}</view>  
                            <u-line direction="col" color="#eee" />  
                            <view class="item active" @click="confirm">{{params.confirmText}}</view>  
                        </template>  
                        <template v-else>  
                            <view class="item active" style="width: 500rpx;" @click="confirm">{{params.confirmText}}</view>  
                        </template>  
                    </view>  
                </view>  
            </template>  
            <!-- 自定义弹窗 -->  
            <template v-else-if="params.type === 3">  
                <view class="rich-box">  
                    <rich-text :nodes="params.content"></rich-text>  
                </view>  
            </template>

关键点在于逻辑,因为要使用诸如uni.showModel 这样的api来实现弹窗效果,需要进行api封装, 添加显示 show() 隐藏 hide() 的方法,另外需要将点击按钮后的回调传给api,使用了uni.navigateTo 的事件发送。页面跳转的方式不适用于h5,所以h5的需要单独处理(h5的弹窗其实是一个dom节点。使用dom操作),弹窗展示后需要重置数据,不然下个弹窗会出现上个弹窗的信息

import Vue from 'vue';  
import globalPopup from './globalPopup.vue'  

class GlobalPopup {  
    constructor () {  
        const PopupVue = Vue.extend(globalPopup);  
        this.popupDom = new PopupVue()  
    }  
       // 弹窗成功后需要重置popupConfig数据  
    init(){  
        const config = {  
            type: 1, // 弹窗类型(1、提交反馈弹窗 2、modal弹窗 3、自定义弹窗(设为此后其他参数无效))  
            showCancel: false, // 是否显示取消按钮  
            confirmText:'确定', // 确定按钮文字  
            cancelText:'取消', // 取消按钮文字  
            closeOpacity:false,// 点击遮罩是否关闭弹窗  
            title: '', // 标题  
            content: '' ,// 内容文本  
            icon: 1// 反馈弹窗状态 (1、成功 2、失败 3、正常)  
        }  
        Vue.prototype.$store.dispatch('updatePopupConfig',config)  
    }  
    // 显示弹窗  
    show (params) {  
        let that = this;  
        // Vue.store 传递参数  
        Vue.prototype.$store.dispatch('updatePopupConfig',params)  
        // #ifdef APP-PLUS  
            uni.navigateTo({  
                url: '/pages/globalPopup/globalPopup',  
                events:{  
                    confirm: function(data) {  
                      that.init()  
                      params.confirm && params.confirm()  
                    },  
                    cancel: function(data) {  
                      that.init()  
                      params.cancel && params.cancel()  
                    }  
                }  
            })  
        // #endif  

        // #ifdef H5  
        this.popupDom.cancel = params?.cancel || this.popupDom.cancel;  
        this.popupDom.confirm = params?.confirm || this.popupDom.confirm;  
        this.popupDom.vm = this.popupDom.$mount();  
        this.popupDom.show = true;  
        const lastEl = document.body.lastElementChild;  
        if(lastEl.id !== 'popup-box'){  
            setTimeout(()=>{  
                document.body.appendChild(that.popupDom.vm.$el)  
            })  
        }  
        // #endif  

    };  

    // 隐藏弹窗 h5弹窗调用回调后需要手动隐藏弹窗(因为无法在回调中获取对象本身,有大佬可以自行优化)  
    hide () {  
        // #ifdef H5  
        let that = this;  
        this.popupDom.show = false;  
        const lastEl = document.body.lastElementChild;  
        if(lastEl.id === 'popup-box'){  
            setTimeout(()=>{  
                document.body.removeChild(lastEl)  
                that.init()  
            },500)  
        }  
        // #endif  
    }  
}

将事件注册到全局
main.js 添加

import globalPopup from '@/pages/globalPopup/globalPopup.js'   
Vue.prototype.$popup = globalPopup;  

3、效果展示

this.$popup.show({  
    title:'提交成功',  
    content:'请等待确认',  
    confirm:()=>{  
        // #ifdef H5  
        this.$popup.hide()  
        // #endif             
    }  
})

2023-6-9 更新

一直想把小程序的全局弹窗也做了,原计划把小程序和h5封装为同一个方法,即使用vue的全局注册功能,将自定义弹窗注册为一个全局组件,但是发现小程序不像h5一样可以操作dom,即使注册了要在页面中使用还是得用标签加上,找了很多资料都没有类似js添加dom的操作,知道发现一个插件vue-inset-loader,作者使用sfc模板在编译阶段指定位置插入自定义内容,参考文档,解决了我的困扰。
但是在使用中还是发现了不少问题,如文件只能放在components文件夹中,数据传输只能用vuex,猜测可能是uni的easycom 配置影响,如果有大佬明白,还请告知一下。
还有之前一直存在的一个问题,在h5弹窗调用回调后需要手动隐藏弹窗(因为无法在回调中获取对象本身),当时自己弄了半天,结果今天意外就找到了解决办法,那就是把方法挂载到vuex中,通过跨页面调用实现回调!

已将该插件放到插件市场,需要的可以访问查看

本篇探讨一种全局弹出的封装方法,大佬们可以在此基础上优化使用,源码在附件中

收起阅读 »

基于Vue3和TypeScript的高效UI组件库fant-mini-plus

vue3 uni_app

介绍

<p align="center">
<img alt="logo" src="http://historysoa.oss-cn-hongkong.aliyuncs.com/fant-mini-plus/logo.png" width="120" height="120" style="margin-bottom: 10px;border-radius:30%;overflow:hidden">
</p>

<h1 align="center">FANT-MINI-PLUS</h1>

<p align="center">一个适用于 uni-app 平台的基于 vue3 的前端UI框架</p>

FantMiniPlus是一个基于Vue3和TypeScript的uni-app高效UI组件库,支持vue3组合式API,提供丰富的组件和样式,帮助开发者快速构建高质量的移动应用。

官方文档:https://fant-mini-plus.top

插件市场地址:点我

开发计划(规划中)

关于开发计划的问题或者建议请先到Gitee或者Github提出issue,或者在评论区发表评论,方便我记录问题以及安排后续的开发计划。(组件或者模板使用上有什么问题,希望增加什么组件或者模板页面都可以提)

预览

扫描下方小程序码,体验演示示例:

<p align="center" style="display:flex;justify-content:space-between">
<img alt="logo" src="http://historysoa.oss-cn-hongkong.aliyuncs.com/fant-mini-plus/miniprogram.jpg" width="240" height="240" style="margin-bottom: 10px;border-radius:30%;overflow:hidden">
<img alt="logo" src="http://historysoa.oss-cn-hongkong.aliyuncs.com/fant-mini-plus/alipay.png" width="240" height="240" style="margin-bottom: 10px;border-radius:30%;overflow:hidden">
</p>

快速上手

演示项目:Vue3-Uni-TS-Template基础模板

介绍

通过本章节你可以了解到 fant-mini-plus 的安装方法和基本使用姿势。

uni_modules

安装

fant-mini-plus 支持 uni_modules 规范,已经上架到 uni-app 的插件市场,故我们推荐使用 uni_modules 的方式引入,方便更新。

uni-app插件市场选择使用HBuildX导入,或者选择手动在src目录下创建uni_modules文件夹并将fant-mini-plus解压到uni_modules中,结构如下:

- uni_modules  
- - - fant-mini-plus 

下载地址:<a href="https://ext.dcloud.net.cn/plugin?id=11489">fant-mini-plus</a>

Tips: 如果需要使用ToastModal组件,则需要安装<a href="https://ext.dcloud.net.cn/plugin?id=805"><span >mp-html</span></a>以支持富文本功能。

配置

1. 引入组件

import { createSSRApp } from 'vue'  
import fantMini from '@/uni_modules/fant-mini-plus'  
import App from './App.vue'  
export function createApp() {  
  const app = createSSRApp(App)  
  app.config.warnHandler = () => null  
  app.use(fantMini)  
  return {  
    app  
  }  
}  

2. 引入fant-mini-plus的主题文件

uni.scss中引入theme.scss

/* uni.scss */  
@import "@/uni_modules/fant-mini-plus/libs/css/theme.scss";

3. 安装sass(如果项目中已经安装sass或者node-sass则此步骤可以忽略)

fant-mini-plus使用scss作为css预编译器,故需在项目中引入,否则无法运行。

# 安装sass  
yarn add sass -D    
# 安装sass-loader  
yarn add sass-loader -D

4. 引入fant-mini-plusiconfont

App.vue中引入iconfont相关文件。

/* App.vue */  
<style>  
@import '@/uni_modules/fant-mini-plus/libs/iconfont/iconfont.css';  
</style>

5. 使用

完成前四步之后就可以开始使用fant-mini-plus了。fant-mini-plus的组件支持easycom规范,故可以直接在.vue中使用,无需在页面内import,也不需要在components内声明,即可在任意页面使用。值得注意的是,uni-app平台不支持全局挂载组件,故LoadingToastModalDatePicker等组件仍需在SFC中显式使用,例如:

<hd-loading></hd-loading>

单独引入

有些伙伴希望可以只引入组件库的其中一个或几个组件,所以这里提供了可以单独引入的组件列表

组件名 介绍 地址
Table 表格组件 支持固定列和排序功能的表格组件 hd-tble
WaterMark 水印组件 支持图片和文字水印 hd-water-mark
Circle 圆环形的进度条组件 圆环形的进度条组件 hd-circle
Progress 进度条组件 进度条组件 hd-progress
hd-transition 动画组件 过渡动画组件 hd-transition
hd-stepper 步进器 步进器组件 hd-stepper
hd-overlay 遮罩层组件 遮罩层组件 hd-overlay
hd-popup 弹出层组件 弹出层组件 hd-popup
hd-icon 图标组件 图标组件 hd-icon
hd-cell 单元格组件 单元格组件 hd-cell
hd-collapse 折叠面板组件 支持手风琴和异步展开 hd-collapse
hd-button 按钮组件 按钮组件 hd-button
hd-area 省市区三级联动选择组件 省市区三级联动选择组件 hd-area
hd-badge 徽标组件 徽标组件 hd-badge
hd-toast 轻提示组件 轻提示组件 hd-toast
hd-calendar 日历组件 用于选择日期或日期区间 hd-calendar
hd-date-picker 日期选择组件 日期选择组件 hd-date-picker
hd-divider 分割线组件 分割线组件 hd-divider

部分组件效果

<img src="https://fant-mini-plus.top/gif/calendar.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/circle.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/countdown.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/datepicker.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/keyboard.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/modal.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/notify.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/progress.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/steper.gif" width="330" height="auto">

继续阅读 »

介绍

<p align="center">
<img alt="logo" src="http://historysoa.oss-cn-hongkong.aliyuncs.com/fant-mini-plus/logo.png" width="120" height="120" style="margin-bottom: 10px;border-radius:30%;overflow:hidden">
</p>

<h1 align="center">FANT-MINI-PLUS</h1>

<p align="center">一个适用于 uni-app 平台的基于 vue3 的前端UI框架</p>

FantMiniPlus是一个基于Vue3和TypeScript的uni-app高效UI组件库,支持vue3组合式API,提供丰富的组件和样式,帮助开发者快速构建高质量的移动应用。

官方文档:https://fant-mini-plus.top

插件市场地址:点我

开发计划(规划中)

关于开发计划的问题或者建议请先到Gitee或者Github提出issue,或者在评论区发表评论,方便我记录问题以及安排后续的开发计划。(组件或者模板使用上有什么问题,希望增加什么组件或者模板页面都可以提)

预览

扫描下方小程序码,体验演示示例:

<p align="center" style="display:flex;justify-content:space-between">
<img alt="logo" src="http://historysoa.oss-cn-hongkong.aliyuncs.com/fant-mini-plus/miniprogram.jpg" width="240" height="240" style="margin-bottom: 10px;border-radius:30%;overflow:hidden">
<img alt="logo" src="http://historysoa.oss-cn-hongkong.aliyuncs.com/fant-mini-plus/alipay.png" width="240" height="240" style="margin-bottom: 10px;border-radius:30%;overflow:hidden">
</p>

快速上手

演示项目:Vue3-Uni-TS-Template基础模板

介绍

通过本章节你可以了解到 fant-mini-plus 的安装方法和基本使用姿势。

uni_modules

安装

fant-mini-plus 支持 uni_modules 规范,已经上架到 uni-app 的插件市场,故我们推荐使用 uni_modules 的方式引入,方便更新。

uni-app插件市场选择使用HBuildX导入,或者选择手动在src目录下创建uni_modules文件夹并将fant-mini-plus解压到uni_modules中,结构如下:

- uni_modules  
- - - fant-mini-plus 

下载地址:<a href="https://ext.dcloud.net.cn/plugin?id=11489">fant-mini-plus</a>

Tips: 如果需要使用ToastModal组件,则需要安装<a href="https://ext.dcloud.net.cn/plugin?id=805"><span >mp-html</span></a>以支持富文本功能。

配置

1. 引入组件

import { createSSRApp } from 'vue'  
import fantMini from '@/uni_modules/fant-mini-plus'  
import App from './App.vue'  
export function createApp() {  
  const app = createSSRApp(App)  
  app.config.warnHandler = () => null  
  app.use(fantMini)  
  return {  
    app  
  }  
}  

2. 引入fant-mini-plus的主题文件

uni.scss中引入theme.scss

/* uni.scss */  
@import "@/uni_modules/fant-mini-plus/libs/css/theme.scss";

3. 安装sass(如果项目中已经安装sass或者node-sass则此步骤可以忽略)

fant-mini-plus使用scss作为css预编译器,故需在项目中引入,否则无法运行。

# 安装sass  
yarn add sass -D    
# 安装sass-loader  
yarn add sass-loader -D

4. 引入fant-mini-plusiconfont

App.vue中引入iconfont相关文件。

/* App.vue */  
<style>  
@import '@/uni_modules/fant-mini-plus/libs/iconfont/iconfont.css';  
</style>

5. 使用

完成前四步之后就可以开始使用fant-mini-plus了。fant-mini-plus的组件支持easycom规范,故可以直接在.vue中使用,无需在页面内import,也不需要在components内声明,即可在任意页面使用。值得注意的是,uni-app平台不支持全局挂载组件,故LoadingToastModalDatePicker等组件仍需在SFC中显式使用,例如:

<hd-loading></hd-loading>

单独引入

有些伙伴希望可以只引入组件库的其中一个或几个组件,所以这里提供了可以单独引入的组件列表

组件名 介绍 地址
Table 表格组件 支持固定列和排序功能的表格组件 hd-tble
WaterMark 水印组件 支持图片和文字水印 hd-water-mark
Circle 圆环形的进度条组件 圆环形的进度条组件 hd-circle
Progress 进度条组件 进度条组件 hd-progress
hd-transition 动画组件 过渡动画组件 hd-transition
hd-stepper 步进器 步进器组件 hd-stepper
hd-overlay 遮罩层组件 遮罩层组件 hd-overlay
hd-popup 弹出层组件 弹出层组件 hd-popup
hd-icon 图标组件 图标组件 hd-icon
hd-cell 单元格组件 单元格组件 hd-cell
hd-collapse 折叠面板组件 支持手风琴和异步展开 hd-collapse
hd-button 按钮组件 按钮组件 hd-button
hd-area 省市区三级联动选择组件 省市区三级联动选择组件 hd-area
hd-badge 徽标组件 徽标组件 hd-badge
hd-toast 轻提示组件 轻提示组件 hd-toast
hd-calendar 日历组件 用于选择日期或日期区间 hd-calendar
hd-date-picker 日期选择组件 日期选择组件 hd-date-picker
hd-divider 分割线组件 分割线组件 hd-divider

部分组件效果

<img src="https://fant-mini-plus.top/gif/calendar.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/circle.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/countdown.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/datepicker.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/keyboard.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/modal.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/notify.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/progress.gif" width="330" height="auto">

<img src="https://fant-mini-plus.top/gif/steper.gif" width="330" height="auto">

收起阅读 »

解决uniapp 语音转文字

uniapp 官方 已经给出文档示例 , 但是还需打包成自定义基座,在这时 还是会返回失败, 还需再script标签对加上 /
/录音
const recorderManager = uni.getRecorderManager();
//播放录音
const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;

详情请看 https://blog.csdn.net/H_hongai/article/details/126364735

继续阅读 »

uniapp 官方 已经给出文档示例 , 但是还需打包成自定义基座,在这时 还是会返回失败, 还需再script标签对加上 /
/录音
const recorderManager = uni.getRecorderManager();
//播放录音
const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;

详情请看 https://blog.csdn.net/H_hongai/article/details/126364735

收起阅读 »

实现底部tab栏中间突起

tabbar

需求

项目用uniapp开发,突然收到一个需求,实现底部tab栏突起的效果

实现

为了实现这样的效果,先查了官方文档,给出了两个方案
1、自定义实现tab栏展示
因为主要开发app,为了体验性还是决定用官方原生tab
2、按官方文档配置tabbar
在官方文档中,可以配置tab栏中间突起;
原文:中间带+号的tabbar模板例子,参考。可跨端,但+号不凸起。如需中间凸起,配置tabbar的midButton。
官方文档
但是有个问题,点击中间不是一个新的页面,还是触发点击事件,在app.vue 中监听。
我的想法是先写一个页面,然后在点击事件中做跳转

export default {  
        onLaunch: function() {  
            // 点击中间按钮  
            uni.onTabBarMidButtonTap(()=>{  
                uni.navigateTo({  
                    url:'/pages/index/index'  
                })  
            })  
                }  
}
"pages": [   
            "path" : "pages/index/home",  
            "style" :                                                                                      
            {  
                "navigationBarTitleText": "首页",  
                "enablePullDownRefresh": false  
            }  

        }  
        {  
            "path" : "pages/index/index",  
            "style" :                                                                                      
            {  
                "navigationBarTitleText": "uniapp",  
                "enablePullDownRefresh": false  
            }  
        }  
    ],

但是明显问题来了,我是切换tab页,不是跳转到新的页面,这样会存在明显的页面跳转动画还有返回。
那我把页面加到page.json的 tabbar中,但这样就会在底部多一个标签选项。
正在我百思不得其解的时候,我注意到tabbar有个属性,visible:是否显示
这样好办了,我把visible设为false,监听改为

uni.onTabBarMidButtonTap(()=>{  
    uni.switchTab({  
        url:'/pages/index/index'  
    })  
})

page.json tabbar设置

    "tabBar": {  
        "borderStyle": "black",  
        "backgroundColor": "#fff",  
        "color": "#8F8F94",  
        "selectedColor": "#1EC2A0",  
        "list": [{  
                    "pagePath": "pages/index/home",  
                    "iconPath": "static/home.png",  
                    "selectedIconPath": "static/homeSelected.png",  
                    "text": "首页"  
                },  
                {  
                    "pagePath": "pages/index/market",  
                    "iconPath": "static/market.png",  
                    "selectedIconPath": "static/market.png",  
                    "text": "商城"  
                },  
                // #ifdef APP-PLUS  
                {  
                    "pagePath": "pages/index/index",  
                    "iconPath": "static/fabu.png",  
                    "selectedIconPath": "static/fabu.png",  
                    "text": "发布",  
                    "visible": false  
                },  
                // #endif  
                // #ifndef APP-PLUS  
                {  
                    "pagePath": "pages/index/index",  
                    "iconPath": "static/fabu.png",  
                    "selectedIconPath": "static/fabu.png",  
                    "text": "发布"  
                },  
                // #endif  
                {  
                    "pagePath": "pages/index/cart",  
                    "iconPath": "static/shopCart.png",  
                    "selectedIconPath": "static/shopCartSelect.png",  
                    "text": "购物车"  
                },  
                {  
                    "pagePath": "pages/index/mine",  
                    "iconPath": "static/mine.png",  
                    "selectedIconPath": "static/mineSelected.png",  
                    "text": "我的"  
                }  
            ],  
        "midButton": {  
            "iconPath": "static/fabu.png",  
            "iconWidth": "60px",  
            "height": "65px"  
        }  
    }

这样就是实现了中间tab页面突起图标加跳转

源码已上传至附件,需要的可以自行下载

继续阅读 »

需求

项目用uniapp开发,突然收到一个需求,实现底部tab栏突起的效果

实现

为了实现这样的效果,先查了官方文档,给出了两个方案
1、自定义实现tab栏展示
因为主要开发app,为了体验性还是决定用官方原生tab
2、按官方文档配置tabbar
在官方文档中,可以配置tab栏中间突起;
原文:中间带+号的tabbar模板例子,参考。可跨端,但+号不凸起。如需中间凸起,配置tabbar的midButton。
官方文档
但是有个问题,点击中间不是一个新的页面,还是触发点击事件,在app.vue 中监听。
我的想法是先写一个页面,然后在点击事件中做跳转

export default {  
        onLaunch: function() {  
            // 点击中间按钮  
            uni.onTabBarMidButtonTap(()=>{  
                uni.navigateTo({  
                    url:'/pages/index/index'  
                })  
            })  
                }  
}
"pages": [   
            "path" : "pages/index/home",  
            "style" :                                                                                      
            {  
                "navigationBarTitleText": "首页",  
                "enablePullDownRefresh": false  
            }  

        }  
        {  
            "path" : "pages/index/index",  
            "style" :                                                                                      
            {  
                "navigationBarTitleText": "uniapp",  
                "enablePullDownRefresh": false  
            }  
        }  
    ],

但是明显问题来了,我是切换tab页,不是跳转到新的页面,这样会存在明显的页面跳转动画还有返回。
那我把页面加到page.json的 tabbar中,但这样就会在底部多一个标签选项。
正在我百思不得其解的时候,我注意到tabbar有个属性,visible:是否显示
这样好办了,我把visible设为false,监听改为

uni.onTabBarMidButtonTap(()=>{  
    uni.switchTab({  
        url:'/pages/index/index'  
    })  
})

page.json tabbar设置

    "tabBar": {  
        "borderStyle": "black",  
        "backgroundColor": "#fff",  
        "color": "#8F8F94",  
        "selectedColor": "#1EC2A0",  
        "list": [{  
                    "pagePath": "pages/index/home",  
                    "iconPath": "static/home.png",  
                    "selectedIconPath": "static/homeSelected.png",  
                    "text": "首页"  
                },  
                {  
                    "pagePath": "pages/index/market",  
                    "iconPath": "static/market.png",  
                    "selectedIconPath": "static/market.png",  
                    "text": "商城"  
                },  
                // #ifdef APP-PLUS  
                {  
                    "pagePath": "pages/index/index",  
                    "iconPath": "static/fabu.png",  
                    "selectedIconPath": "static/fabu.png",  
                    "text": "发布",  
                    "visible": false  
                },  
                // #endif  
                // #ifndef APP-PLUS  
                {  
                    "pagePath": "pages/index/index",  
                    "iconPath": "static/fabu.png",  
                    "selectedIconPath": "static/fabu.png",  
                    "text": "发布"  
                },  
                // #endif  
                {  
                    "pagePath": "pages/index/cart",  
                    "iconPath": "static/shopCart.png",  
                    "selectedIconPath": "static/shopCartSelect.png",  
                    "text": "购物车"  
                },  
                {  
                    "pagePath": "pages/index/mine",  
                    "iconPath": "static/mine.png",  
                    "selectedIconPath": "static/mineSelected.png",  
                    "text": "我的"  
                }  
            ],  
        "midButton": {  
            "iconPath": "static/fabu.png",  
            "iconWidth": "60px",  
            "height": "65px"  
        }  
    }

这样就是实现了中间tab页面突起图标加跳转

源码已上传至附件,需要的可以自行下载

收起阅读 »

HBuilderX连接MuMu模拟器教程

adb mumu模拟器 HBuilderX HBuilderX技巧

第一步 下载MuMu模拟器

下载MuMu模拟器就不介绍了,自行去百度下载,我下载的是安卓6的版本,下载完成后直接安装。

第二步 开始进行adb连接 (连接时请不要关闭MuMu模拟器)

1、打开MuMu模拟器安装路径下的bin文件夹(具体路径为"安装路径的文件夹\emulator\nemu\vmonitor\bin"),然后点击文件夹路径,输入CMD,再点击回车按键呼出CMD运行窗口(如下图);


2、选中路径

3、输入cmd,然后点击回车按键

4、输入以下代码(具体可参考下图):

adb_server.exe connect 127.0.0.1:7555  
adb_server shell

若使用模拟器版本≥2.7.9.0,获取Root权限需要操作:
方法1:设置中心-基本设置-root权限开启,权限同意后,重新进行adb连接(不用重启模拟器)
方法2:执行adb_server.exe connect 127.0.0.1:7555 && adb root,权限同意后,重新进行adb连接(不用重启模拟器)

第三步 配置HBuilderX

1、点开HBuilderX的“设置”


2、点击“运行配置”,把“1”中的adb路径复制在图中的位置,端口号设置为7555,和“4”中的端口号一致

3、开始真机运行

此时可以成功把项目运行到模拟器。

如果文章对您有帮助的话,留个赞在走吧~~~

继续阅读 »

第一步 下载MuMu模拟器

下载MuMu模拟器就不介绍了,自行去百度下载,我下载的是安卓6的版本,下载完成后直接安装。

第二步 开始进行adb连接 (连接时请不要关闭MuMu模拟器)

1、打开MuMu模拟器安装路径下的bin文件夹(具体路径为"安装路径的文件夹\emulator\nemu\vmonitor\bin"),然后点击文件夹路径,输入CMD,再点击回车按键呼出CMD运行窗口(如下图);


2、选中路径

3、输入cmd,然后点击回车按键

4、输入以下代码(具体可参考下图):

adb_server.exe connect 127.0.0.1:7555  
adb_server shell

若使用模拟器版本≥2.7.9.0,获取Root权限需要操作:
方法1:设置中心-基本设置-root权限开启,权限同意后,重新进行adb连接(不用重启模拟器)
方法2:执行adb_server.exe connect 127.0.0.1:7555 && adb root,权限同意后,重新进行adb连接(不用重启模拟器)

第三步 配置HBuilderX

1、点开HBuilderX的“设置”


2、点击“运行配置”,把“1”中的adb路径复制在图中的位置,端口号设置为7555,和“4”中的端口号一致

3、开始真机运行

此时可以成功把项目运行到模拟器。

如果文章对您有帮助的话,留个赞在走吧~~~

收起阅读 »

基于vue3的uni-app路由库uni-mini-router助你实现跳转、传参、拦截等路由功能

vue3 路由 uni_app

介绍

uni-mini-router是一个基于vue3uni-app框架的轻量级路由库,它提供了类似Vue Router的API和功能,可以帮助开发者实现在uni-app中进行路由跳转、传参、拦截等常用操作。

uni-mini-router支持多种跳转方式,包括普通跳转、重定向、切换TabBar页面等。它也提供了一些高级特性,如路由拦截、编程式导航等。

总之,如果你在uni-app开发过程中需要使用到路由功能,可以考虑使用uni-mini-router来简化你的开发工作。

安装uni-mini-router

Yarn
yarn add uni-mini-router -D
npm
npm install uni-mini-router --save

生成路由表

我们提供了两种方式来生成路由表:uni-parse-pagesuni-read-pages-vite,这两种方式都可以实现将pages.json中的路由信息转化为uni-mini-router需要的路由表信息,其中uni-read-pages-vite依赖vite,在编译时将读取pages.json生成的路由表注入全局变量,而uni-parse-pages不依赖vite,在应用每次热重载时都会从pages.json中读取信息生成路由表。

由于uni-app在编译到小程序端时无法触发vite的热更新,所以目前只有使用uni-parse-pages生成路由表才可以实现路由信息热更新的功能。

注意!!!uni-parse-pagesuni-mini-router@0.1.0版本起获得支持,在之前的版本使用会有问题。

以下两种方式二选一:

使用uni-parse-pages生成路由表(0.1.0起支持)

安装

Yarn
yarn add uni-parse-pages -D
npm
npm install uni-parse-pages --save

使用uni-read-pages-vite生成路由表

安装

Yarn
yarn add uni-read-pages-vite
npm
npm install uni-read-pages-vite

配置

配置uni-read-pages-vite

配置 vite.config.ts 通过 define 注入全局变量 查看文档

注意:在 Vite 中使用 define 注入的全局变量并不是热更新的,因为这些变量是在构建时被注入到代码中的,而不是在运行时动态生成的。这意味着如果您更新了page.json,则需要重新构建应用程序才能使更改生效。

配置vite.config.ts
CLI创建的项目配置
//vite.config.ts  
import { defineConfig } from "vite";  
import uni from "@dcloudio/vite-plugin-uni";  
import TransformPages from 'uni-read-pages-vite'  

export default defineConfig({  
  plugins: [uni()],  
  define: {  
    ROUTES: new TransformPages().routes, // 注入路由表  
  }  
});
HbuilderX创建的项目配置
//vite.config.ts  
import { defineConfig } from "vite";  
import uni from "@dcloudio/vite-plugin-uni";  
import TransformPages from 'uni-read-pages-vite'  

export default defineConfig({  
  plugins: [uni()],  
  define: {  
    ROUTES: new TransformPages(__dirname).routes, // 注入路由表  
  }  
});
声明文件type.d.ts

.d.ts文件的作用是描述JavaScript库、模块或其他代码的类型声明和元数据,以便编辑器和开发者能够更好地理解和使用该代码。在编译时,TypeScript编译器会使用.d.ts文件来验证代码正确性,并帮助开发者在开发过程中提供更好的代码提示和自动补全功能。

在项目src目录下(HbuilderX创建的项目可以在根目录下)创建type.d.ts文件。

//type.d.ts  
declare const ROUTES: []

配置uni-mini-router

项目src目录下(HbuilderX创建的项目可以在根目录下)创建router文件夹,并在该文件夹创建index.ts

配置router/index.ts

根据生成路由表方式的不同,我们这里也提供了两种配置router的方式,也是二选一

uni-parse-pages

import { createRouter } from 'uni-mini-router'  
// 导入pages.json  
import pagesJson from '../pages.json'  
// 引入uni-parse-pages  
import pagesJsonToRoutes from 'uni-parse-pages'  
// 生成路由表  
const routes = pagesJsonToRoutes(pagesJson)  
const router = createRouter({  
  routes: [...routes] // 路由表信息  
})  
export default router

uni-read-pages-vite

此处的ROUTES就是配置vite.config.ts步骤中注入的

import { createRouter } from 'uni-mini-router'  
const router = createRouter({  
  routes: [...ROUTES] // 路由表信息  
})  
export default router

配置main.ts

import { createSSRApp } from 'vue'  
import App from './App.vue'  
import router from './router'  
export function createApp() {  
  const app = createSSRApp(App)  
  app.use(router)  
  return {  
    app  
  }  
}

配置pages.json

在pages.json中为页面路由指定name字段后,即可以使用name跳转

注意:此处定义的name字段必须全局唯一。

//  pages.json  
{  
  "pages": [{  
      "path": "pages/home/Home",  
      "name": "home", // 路由 name 用于命名路由的跳转  
      "style": {  
        "mp-alipay": {  
          "allowsBounceVertical": "NO"  
        },  
        "navigationBarTitleText": "首页"  
      }  
    },  
    {  
      "path": "pages/login/Login",  
      "name": "login",  
      "style": {  
        "mp-alipay": {  
          "allowsBounceVertical": "NO"  
        },  
        "navigationBarTitleText": ""  
      }  
    },  
    {  
      "path": "pages/mine/Mine",  
      "name": "mine",  
      "style": {  
        "navigationBarTitleText": "",  
        "navigationBarBackgroundColor": "#E7F0FF"  
      }  
    }  
  ],  
  "tabBar": {  
    "color": "#bfbfbf",  
    "selectedColor": "#0165FF",  
    "backgroundColor": "#ffffff",  
    "list": [{  
        "pagePath": "pages/home/Home",  
        "iconPath": "static/icon_home.png",  
        "selectedIconPath": "static/icon_home_selected.png",  
        "text": "首页"  
      },  
      {  
        "pagePath": "pages/mine/Mine",  
        "iconPath": "static/icon_mine.png",  
        "selectedIconPath": "static/icon_mine_selected.png",  
        "text": "我的"  
      }  
    ]  
  },  
  "globalStyle": {  
    "navigationBarTextStyle": "black",  
    "navigationBarBackgroundColor": "#FFF",  
    "backgroundColor": "#F8F8F8"  
  }  
}

配置自动按需导入(可选)

unplugin-auto-import:是一个为 ViteWebpackRollupesbuild 按需自动导入 API,支持 TypeScript的插件,我们基于此插件实现自动按需导入。

不使用按需导入,则需要手动import

import { useRouter } from 'uni-mini-router'  
const router = useRouter()  
router.push('/')

使用按需导入后

const router = useRouter()  
router.push('/')

安装unplugin-auto-import

yarn add uni-mini-router -D

配置unplugin-auto-import

详细配置方案见unplugin-auto-import,这里给出支持uni-mini-router的简易配置

//vite.config.ts  
import { defineConfig } from 'vite'  
import TransformPages from 'uni-read-pages-vite'  
import uni from '@dcloudio/vite-plugin-uni'  
import AutoImport from 'unplugin-auto-import/vite'  
export default defineConfig({  
  base: './',  
  plugins: [  
    uni(),  
    AutoImport({  
      imports: [  
        'vue',  
        'uni-app',  
        'pinia',  
        {  
          from: 'uni-mini-router',  
          imports: ['createRouter', 'useRouter', 'useRoute']  
        }  
      ],  
      dts: 'src/auto-imports.d.ts', // 这里src目录必须是已存在的,如果是HbuilderX创建的项目是没有src目录的,可以配置为 dts: 'auto-imports.d.ts'  
      eslintrc: {  
        enabled: true,  
        globalsPropValue: true  
      }  
    })  
  ],  
  define: {  
    ROUTES: new TransformPages().routes  
  }  
})

总结

unplugin-auto-import 可以帮助我们实现按需自动导入第三方库的API,提升开发效率,但是它也同样存在一些缺点,例如:

  • 可能会影响代码可读性:自动导入模块可能会导致代码可读性降低,因为开发者可能不知道哪些模块被自动导入了。

  • 可能会导致性能问题:自动导入模块可能会导致性能问题,因为它需要扫描整个代码库来查找缺失的模块。

所以在提升开发效率的同时也要兼顾可读性和性能问题,尽量将一些被广泛认知和使用、不用关注实现、不变的内容作为自动按需引入的对象,而项目内的代码如果自动按需引入是否会增加开发人员的心智负担,则需要我们做出相应的权衡。

使用

编程式导航

注意:这里nameparams搭配使用,而path 可以与 query 一起使用。

基础用法

<script setup lang="ts">  
import { ref } from 'vue'  
import { useRouter } from 'uni-mini-router'  
import { getCurrentInstance } from 'vue'  

// 使用hooks(推荐)  
let router = useRouter()  

// 或者 使用全局挂载的router  
router = instence?.appContext.config.globalProperties.$Router  

// 字符串路径  
router.push('/user')  

// 带有路径的对象  
router.push({ path: '/user' })  

// 命名的路由,并加上参数,让路由建立 url  
router.push({ name: 'user', params: { username: 'eduardo' } })  

// 带查询参数,结果是 /user?username=eduardo  
router.push({ path: '/user', query: { username: 'eduardo' } })  

</script>

在user.vue接收传入的对象参数

<script setup lang="ts">  
onLoad((option) => {  
  if (option && option.username) {  
    const username = option.username  
  }  
})  
</script>

传递对象参数

url有长度限制,太长的字符串会传递失败,可改用窗体通信全局变量,另外参数中出现空格等特殊字符时需要对参数进行编码,如下为使用encodeURIComponent对参数进行编码的示例。

<script setup lang="ts">  
import { ref } from 'vue'  
import { useRouter } from 'uni-mini-router'  
import { getCurrentInstance } from 'vue'  

let router = useRouter()  

const user = {  
  name:'小星星',  
  label:"小熊熊"  
}  

// 命名的路由,传递对象参数  
router.push({ name: 'user', params: { user: encodeURIComponent(JSON.stringify(user)) } })  

// path+query,传递对象参数  
router.push({ path: '/user', query: { user: encodeURIComponent(JSON.stringify(user)) } })  

</script>

在user.vue接收传入的对象参数

<script setup lang="ts">  
onLoad((option) => {  
  if (option && option.user) {  
    const user = JSON.parse(decodeURIComponent(option.user))  
  }  
})  

// 返回  
function back() {  
  router.back()  
}  
</script>

导航守卫

uni-mini-router支持全局前置导航守卫 beforeEach全局后置导航守卫 afterEach,主要用来通过跳转或取消的方式守卫导航。

全局前置守卫 beforeEach

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = createRouter({ ... })  

router.beforeEach((to, from, next) => {  
  // next入参 false 以取消导航  
  next(false)  
})
beforeEach守卫方法接收三个参数:
  • to: 即将要进入的目标
  • from: 当前导航正要离开的路由
  • next: 用于reslove beforeEach钩子,需要确保 next 在导航守卫中都被严格调用一次-
    • next(): 执行默认路由跳转逻辑
    • next(false): 终止跳转逻辑
    • next({ path: '/' }): 跳转到不同的页面
    • next({ path: '/', navType: 'replaceAll' }): 改变当前跳转类型并跳转到不同的页面,可以通过navType指定新的跳转类型。(实例为中断当前导航,改用replaceAll方法跳转到新的页面)

全局后置钩子 afterEach

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身

const router = createRouter({ ... })  

router.afterEach((to, from) => {  
  console.log(to)  
  console.log(from)  
})

它对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。

API 文档

createRouter

▸ createRouter(options): Router

创建一个可以被 Vue 应用使用的 Router 实例。

参数
名称 类型 描述
options RouterOptions RouterOptions
返回值

Router

useRouter

▸ useRouter(): Router

返回路由器实例。相当于在模板中使用 \$Router。

不可以脱离 Vue 上下文使用

返回值

Router

useRoute

▸ useRoute(): Route

返回当前的路由地址信息。相当于在模板中使用 \$Route。

不可以脱离 Vue 上下文使用,且只能在页面mount之后才可与使用。当使用场景为外部链接跳转进入或H5页面刷新时,默认从当前链接中取得query参数并放在Routequery字段中,这种场景建议走onLoad声明周期获取参数。

返回值

Route

Router实例方法

push方法

▸ router.push(target:RouteLocationRaw): void

保留当前页面,跳转到应用内的某个页面,相当于使用 uni.navigateTo(OBJECT)

pushTab方法

▸ router.pushTab(target:RouteLocationRaw): void

跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,相当于使用 uni.switchTab(OBJECT)

replace方法

▸ router.replace(target:RouteLocationRaw): void

关闭当前页面,跳转到应用内的某个页面,相当于使用 uni.redirectTo(OBJECT)

replaceAll方法

▸ router.replaceAll(target:RouteLocationRaw): void

关闭所有页面,打开到应用内的某个页面,相当于使用 uni.reLaunch(OBJECT)

back方法

▸ router.back(level?: number): void

关闭当前页面,返回上一页面或多级页面,相当于使用 uni.navigateBack(OBJECT)

演示项目:Vue3-Uni-TS-Template基础模板

使用文档:地址

插件市场地址:uni-mini-router

继续阅读 »

介绍

uni-mini-router是一个基于vue3uni-app框架的轻量级路由库,它提供了类似Vue Router的API和功能,可以帮助开发者实现在uni-app中进行路由跳转、传参、拦截等常用操作。

uni-mini-router支持多种跳转方式,包括普通跳转、重定向、切换TabBar页面等。它也提供了一些高级特性,如路由拦截、编程式导航等。

总之,如果你在uni-app开发过程中需要使用到路由功能,可以考虑使用uni-mini-router来简化你的开发工作。

安装uni-mini-router

Yarn
yarn add uni-mini-router -D
npm
npm install uni-mini-router --save

生成路由表

我们提供了两种方式来生成路由表:uni-parse-pagesuni-read-pages-vite,这两种方式都可以实现将pages.json中的路由信息转化为uni-mini-router需要的路由表信息,其中uni-read-pages-vite依赖vite,在编译时将读取pages.json生成的路由表注入全局变量,而uni-parse-pages不依赖vite,在应用每次热重载时都会从pages.json中读取信息生成路由表。

由于uni-app在编译到小程序端时无法触发vite的热更新,所以目前只有使用uni-parse-pages生成路由表才可以实现路由信息热更新的功能。

注意!!!uni-parse-pagesuni-mini-router@0.1.0版本起获得支持,在之前的版本使用会有问题。

以下两种方式二选一:

使用uni-parse-pages生成路由表(0.1.0起支持)

安装

Yarn
yarn add uni-parse-pages -D
npm
npm install uni-parse-pages --save

使用uni-read-pages-vite生成路由表

安装

Yarn
yarn add uni-read-pages-vite
npm
npm install uni-read-pages-vite

配置

配置uni-read-pages-vite

配置 vite.config.ts 通过 define 注入全局变量 查看文档

注意:在 Vite 中使用 define 注入的全局变量并不是热更新的,因为这些变量是在构建时被注入到代码中的,而不是在运行时动态生成的。这意味着如果您更新了page.json,则需要重新构建应用程序才能使更改生效。

配置vite.config.ts
CLI创建的项目配置
//vite.config.ts  
import { defineConfig } from "vite";  
import uni from "@dcloudio/vite-plugin-uni";  
import TransformPages from 'uni-read-pages-vite'  

export default defineConfig({  
  plugins: [uni()],  
  define: {  
    ROUTES: new TransformPages().routes, // 注入路由表  
  }  
});
HbuilderX创建的项目配置
//vite.config.ts  
import { defineConfig } from "vite";  
import uni from "@dcloudio/vite-plugin-uni";  
import TransformPages from 'uni-read-pages-vite'  

export default defineConfig({  
  plugins: [uni()],  
  define: {  
    ROUTES: new TransformPages(__dirname).routes, // 注入路由表  
  }  
});
声明文件type.d.ts

.d.ts文件的作用是描述JavaScript库、模块或其他代码的类型声明和元数据,以便编辑器和开发者能够更好地理解和使用该代码。在编译时,TypeScript编译器会使用.d.ts文件来验证代码正确性,并帮助开发者在开发过程中提供更好的代码提示和自动补全功能。

在项目src目录下(HbuilderX创建的项目可以在根目录下)创建type.d.ts文件。

//type.d.ts  
declare const ROUTES: []

配置uni-mini-router

项目src目录下(HbuilderX创建的项目可以在根目录下)创建router文件夹,并在该文件夹创建index.ts

配置router/index.ts

根据生成路由表方式的不同,我们这里也提供了两种配置router的方式,也是二选一

uni-parse-pages

import { createRouter } from 'uni-mini-router'  
// 导入pages.json  
import pagesJson from '../pages.json'  
// 引入uni-parse-pages  
import pagesJsonToRoutes from 'uni-parse-pages'  
// 生成路由表  
const routes = pagesJsonToRoutes(pagesJson)  
const router = createRouter({  
  routes: [...routes] // 路由表信息  
})  
export default router

uni-read-pages-vite

此处的ROUTES就是配置vite.config.ts步骤中注入的

import { createRouter } from 'uni-mini-router'  
const router = createRouter({  
  routes: [...ROUTES] // 路由表信息  
})  
export default router

配置main.ts

import { createSSRApp } from 'vue'  
import App from './App.vue'  
import router from './router'  
export function createApp() {  
  const app = createSSRApp(App)  
  app.use(router)  
  return {  
    app  
  }  
}

配置pages.json

在pages.json中为页面路由指定name字段后,即可以使用name跳转

注意:此处定义的name字段必须全局唯一。

//  pages.json  
{  
  "pages": [{  
      "path": "pages/home/Home",  
      "name": "home", // 路由 name 用于命名路由的跳转  
      "style": {  
        "mp-alipay": {  
          "allowsBounceVertical": "NO"  
        },  
        "navigationBarTitleText": "首页"  
      }  
    },  
    {  
      "path": "pages/login/Login",  
      "name": "login",  
      "style": {  
        "mp-alipay": {  
          "allowsBounceVertical": "NO"  
        },  
        "navigationBarTitleText": ""  
      }  
    },  
    {  
      "path": "pages/mine/Mine",  
      "name": "mine",  
      "style": {  
        "navigationBarTitleText": "",  
        "navigationBarBackgroundColor": "#E7F0FF"  
      }  
    }  
  ],  
  "tabBar": {  
    "color": "#bfbfbf",  
    "selectedColor": "#0165FF",  
    "backgroundColor": "#ffffff",  
    "list": [{  
        "pagePath": "pages/home/Home",  
        "iconPath": "static/icon_home.png",  
        "selectedIconPath": "static/icon_home_selected.png",  
        "text": "首页"  
      },  
      {  
        "pagePath": "pages/mine/Mine",  
        "iconPath": "static/icon_mine.png",  
        "selectedIconPath": "static/icon_mine_selected.png",  
        "text": "我的"  
      }  
    ]  
  },  
  "globalStyle": {  
    "navigationBarTextStyle": "black",  
    "navigationBarBackgroundColor": "#FFF",  
    "backgroundColor": "#F8F8F8"  
  }  
}

配置自动按需导入(可选)

unplugin-auto-import:是一个为 ViteWebpackRollupesbuild 按需自动导入 API,支持 TypeScript的插件,我们基于此插件实现自动按需导入。

不使用按需导入,则需要手动import

import { useRouter } from 'uni-mini-router'  
const router = useRouter()  
router.push('/')

使用按需导入后

const router = useRouter()  
router.push('/')

安装unplugin-auto-import

yarn add uni-mini-router -D

配置unplugin-auto-import

详细配置方案见unplugin-auto-import,这里给出支持uni-mini-router的简易配置

//vite.config.ts  
import { defineConfig } from 'vite'  
import TransformPages from 'uni-read-pages-vite'  
import uni from '@dcloudio/vite-plugin-uni'  
import AutoImport from 'unplugin-auto-import/vite'  
export default defineConfig({  
  base: './',  
  plugins: [  
    uni(),  
    AutoImport({  
      imports: [  
        'vue',  
        'uni-app',  
        'pinia',  
        {  
          from: 'uni-mini-router',  
          imports: ['createRouter', 'useRouter', 'useRoute']  
        }  
      ],  
      dts: 'src/auto-imports.d.ts', // 这里src目录必须是已存在的,如果是HbuilderX创建的项目是没有src目录的,可以配置为 dts: 'auto-imports.d.ts'  
      eslintrc: {  
        enabled: true,  
        globalsPropValue: true  
      }  
    })  
  ],  
  define: {  
    ROUTES: new TransformPages().routes  
  }  
})

总结

unplugin-auto-import 可以帮助我们实现按需自动导入第三方库的API,提升开发效率,但是它也同样存在一些缺点,例如:

  • 可能会影响代码可读性:自动导入模块可能会导致代码可读性降低,因为开发者可能不知道哪些模块被自动导入了。

  • 可能会导致性能问题:自动导入模块可能会导致性能问题,因为它需要扫描整个代码库来查找缺失的模块。

所以在提升开发效率的同时也要兼顾可读性和性能问题,尽量将一些被广泛认知和使用、不用关注实现、不变的内容作为自动按需引入的对象,而项目内的代码如果自动按需引入是否会增加开发人员的心智负担,则需要我们做出相应的权衡。

使用

编程式导航

注意:这里nameparams搭配使用,而path 可以与 query 一起使用。

基础用法

<script setup lang="ts">  
import { ref } from 'vue'  
import { useRouter } from 'uni-mini-router'  
import { getCurrentInstance } from 'vue'  

// 使用hooks(推荐)  
let router = useRouter()  

// 或者 使用全局挂载的router  
router = instence?.appContext.config.globalProperties.$Router  

// 字符串路径  
router.push('/user')  

// 带有路径的对象  
router.push({ path: '/user' })  

// 命名的路由,并加上参数,让路由建立 url  
router.push({ name: 'user', params: { username: 'eduardo' } })  

// 带查询参数,结果是 /user?username=eduardo  
router.push({ path: '/user', query: { username: 'eduardo' } })  

</script>

在user.vue接收传入的对象参数

<script setup lang="ts">  
onLoad((option) => {  
  if (option && option.username) {  
    const username = option.username  
  }  
})  
</script>

传递对象参数

url有长度限制,太长的字符串会传递失败,可改用窗体通信全局变量,另外参数中出现空格等特殊字符时需要对参数进行编码,如下为使用encodeURIComponent对参数进行编码的示例。

<script setup lang="ts">  
import { ref } from 'vue'  
import { useRouter } from 'uni-mini-router'  
import { getCurrentInstance } from 'vue'  

let router = useRouter()  

const user = {  
  name:'小星星',  
  label:"小熊熊"  
}  

// 命名的路由,传递对象参数  
router.push({ name: 'user', params: { user: encodeURIComponent(JSON.stringify(user)) } })  

// path+query,传递对象参数  
router.push({ path: '/user', query: { user: encodeURIComponent(JSON.stringify(user)) } })  

</script>

在user.vue接收传入的对象参数

<script setup lang="ts">  
onLoad((option) => {  
  if (option && option.user) {  
    const user = JSON.parse(decodeURIComponent(option.user))  
  }  
})  

// 返回  
function back() {  
  router.back()  
}  
</script>

导航守卫

uni-mini-router支持全局前置导航守卫 beforeEach全局后置导航守卫 afterEach,主要用来通过跳转或取消的方式守卫导航。

全局前置守卫 beforeEach

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = createRouter({ ... })  

router.beforeEach((to, from, next) => {  
  // next入参 false 以取消导航  
  next(false)  
})
beforeEach守卫方法接收三个参数:
  • to: 即将要进入的目标
  • from: 当前导航正要离开的路由
  • next: 用于reslove beforeEach钩子,需要确保 next 在导航守卫中都被严格调用一次-
    • next(): 执行默认路由跳转逻辑
    • next(false): 终止跳转逻辑
    • next({ path: '/' }): 跳转到不同的页面
    • next({ path: '/', navType: 'replaceAll' }): 改变当前跳转类型并跳转到不同的页面,可以通过navType指定新的跳转类型。(实例为中断当前导航,改用replaceAll方法跳转到新的页面)

全局后置钩子 afterEach

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身

const router = createRouter({ ... })  

router.afterEach((to, from) => {  
  console.log(to)  
  console.log(from)  
})

它对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。

API 文档

createRouter

▸ createRouter(options): Router

创建一个可以被 Vue 应用使用的 Router 实例。

参数
名称 类型 描述
options RouterOptions RouterOptions
返回值

Router

useRouter

▸ useRouter(): Router

返回路由器实例。相当于在模板中使用 \$Router。

不可以脱离 Vue 上下文使用

返回值

Router

useRoute

▸ useRoute(): Route

返回当前的路由地址信息。相当于在模板中使用 \$Route。

不可以脱离 Vue 上下文使用,且只能在页面mount之后才可与使用。当使用场景为外部链接跳转进入或H5页面刷新时,默认从当前链接中取得query参数并放在Routequery字段中,这种场景建议走onLoad声明周期获取参数。

返回值

Route

Router实例方法

push方法

▸ router.push(target:RouteLocationRaw): void

保留当前页面,跳转到应用内的某个页面,相当于使用 uni.navigateTo(OBJECT)

pushTab方法

▸ router.pushTab(target:RouteLocationRaw): void

跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,相当于使用 uni.switchTab(OBJECT)

replace方法

▸ router.replace(target:RouteLocationRaw): void

关闭当前页面,跳转到应用内的某个页面,相当于使用 uni.redirectTo(OBJECT)

replaceAll方法

▸ router.replaceAll(target:RouteLocationRaw): void

关闭所有页面,打开到应用内的某个页面,相当于使用 uni.reLaunch(OBJECT)

back方法

▸ router.back(level?: number): void

关闭当前页面,返回上一页面或多级页面,相当于使用 uni.navigateBack(OBJECT)

演示项目:Vue3-Uni-TS-Template基础模板

使用文档:地址

插件市场地址:uni-mini-router

收起阅读 »

ios系统数字键盘问题

可在input时间判断最后一位是 小数点 或 零时 直接return

> <input v-model="quantity" placeholder="请输入" @input="handleNum" inputmode="decimal" type="digit" step="0.0000001" @blur="numBlur1()" style="border:0px;outline:none;"/>

> handleNum(){
const str = this.netQuantity + ''
const flag = str.indexOf('.')
const flag1 = str.lastIndexOf('.')
const flag2 = str.lastIndexOf('0')
if(flag > 0 && flag1 === str.length-1){
if(flag === flag1) {
return
} else {
const toast = this.$createToast({
txt: '请输入正确的数字格式',
type: 'info'
})
toast.show()
this.netQuantity = 0
return
}
}
if(flag2 === str.length-1){
return
}
}

继续阅读 »

可在input时间判断最后一位是 小数点 或 零时 直接return

> <input v-model="quantity" placeholder="请输入" @input="handleNum" inputmode="decimal" type="digit" step="0.0000001" @blur="numBlur1()" style="border:0px;outline:none;"/>

> handleNum(){
const str = this.netQuantity + ''
const flag = str.indexOf('.')
const flag1 = str.lastIndexOf('.')
const flag2 = str.lastIndexOf('0')
if(flag > 0 && flag1 === str.length-1){
if(flag === flag1) {
return
} else {
const toast = this.$createToast({
txt: '请输入正确的数字格式',
type: 'info'
})
toast.show()
this.netQuantity = 0
return
}
}
if(flag2 === str.length-1){
return
}
}

收起阅读 »