
npm i cheerio之后,在本地运行云函数ok,云上执行失败
问题根因:
应该在这个云函数的目录下面执行:npm init -y 和 npm i cheerio
还原我出错的原因是在项目的根目录下面执行了这两行,结果本地执行可以执行,但是云函数的package.json中间没有创建依赖信息,导致的问题。
问题根因:
应该在这个云函数的目录下面执行:npm init -y 和 npm i cheerio
还原我出错的原因是在项目的根目录下面执行了这两行,结果本地执行可以执行,但是云函数的package.json中间没有创建依赖信息,导致的问题。

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
收起阅读 »
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
介绍
<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: 如果需要使用
Toast
和Modal
组件,则需要安装<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-plus
的iconfont
在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平台不支持全局挂载组件,故Loading
、Toast
、Modal
、DatePicker
等组件仍需在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: 如果需要使用
Toast
和Modal
组件,则需要安装<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-plus
的iconfont
在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平台不支持全局挂载组件,故Loading
、Toast
、Modal
、DatePicker
等组件仍需在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栏中间突起
需求
项目用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模拟器教程
第一步 下载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助你实现跳转、传参、拦截等路由功能
介绍
uni-mini-router
是一个基于vue3
和uni-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-pages和uni-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-pages
在uni-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:是一个为 Vite
、Webpack
、Rollup
和 esbuild
按需自动导入 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,提升开发效率,但是它也同样存在一些缺点,例如:
-
可能会影响代码可读性:自动导入模块可能会导致代码可读性降低,因为开发者可能不知道哪些模块被自动导入了。
-
可能会导致性能问题:自动导入模块可能会导致性能问题,因为它需要扫描整个代码库来查找缺失的模块。
所以在提升开发效率的同时也要兼顾可读性和性能问题,尽量将一些被广泛认知和使用、不用关注实现、不变的内容作为自动按需引入的对象,而项目内的代码如果自动按需引入是否会增加开发人员的心智负担,则需要我们做出相应的权衡。
使用
编程式导航
注意:这里
name
和params
搭配使用,而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
: 用于reslovebeforeEach
钩子,需要确保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参数并放在Route
的query
字段中,这种场景建议走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
是一个基于vue3
和uni-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-pages和uni-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-pages
在uni-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:是一个为 Vite
、Webpack
、Rollup
和 esbuild
按需自动导入 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,提升开发效率,但是它也同样存在一些缺点,例如:
-
可能会影响代码可读性:自动导入模块可能会导致代码可读性降低,因为开发者可能不知道哪些模块被自动导入了。
-
可能会导致性能问题:自动导入模块可能会导致性能问题,因为它需要扫描整个代码库来查找缺失的模块。
所以在提升开发效率的同时也要兼顾可读性和性能问题,尽量将一些被广泛认知和使用、不用关注实现、不变的内容作为自动按需引入的对象,而项目内的代码如果自动按需引入是否会增加开发人员的心智负担,则需要我们做出相应的权衡。
使用
编程式导航
注意:这里
name
和params
搭配使用,而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
: 用于reslovebeforeEach
钩子,需要确保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参数并放在Route
的query
字段中,这种场景建议走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
}
}