
关于官方插件市场,这件事我不得不发个帖子炫耀一下!@
我算是ChatGPT第一波开发者,2022年12月初的时候,分享了自己写的一套ChatGPT问答的前端模板,在uni的插件市场发布,并获得不少好评,如下图。

后来很多开发者都是基于我的这套模板进行二次开发,或者是借鉴了部分思路。
但是让我没想到的是,在三月初的时候,官方突然给我下线了,那时候正是ChatGPT二次火爆的时候。
项目地址如下:ChatGPT专业版模板
后来我发现官方插件市场同类产品越来越多,而且UI界面都很熟悉,而现在uni官方也上线了自己的对话项目:uni-ai-chat
不知何意,现在想想,如果那时候没下线我的模板,下载量应该位居于首的吧。
虽然有点可惜,但是过去的都过去了,如果官方看到这个帖子,当我放屁就好了,不用管,只是发个牢骚而已。
我算是ChatGPT第一波开发者,2022年12月初的时候,分享了自己写的一套ChatGPT问答的前端模板,在uni的插件市场发布,并获得不少好评,如下图。
后来很多开发者都是基于我的这套模板进行二次开发,或者是借鉴了部分思路。
但是让我没想到的是,在三月初的时候,官方突然给我下线了,那时候正是ChatGPT二次火爆的时候。
项目地址如下:ChatGPT专业版模板
后来我发现官方插件市场同类产品越来越多,而且UI界面都很熟悉,而现在uni官方也上线了自己的对话项目:uni-ai-chat
不知何意,现在想想,如果那时候没下线我的模板,下载量应该位居于首的吧。
虽然有点可惜,但是过去的都过去了,如果官方看到这个帖子,当我放屁就好了,不用管,只是发个牢骚而已。
收起阅读 »
【公告】关于5月31日阿里云版uniCloud云函数响应缓慢的故障说明
5月31日,部分开发者反应阿里云版云函数响应缓慢,DCloud紧急联系阿里云快速治理恢复,详见https://ask.dcloud.net.cn/question/170939。
业务恢复后,阿里云内部也对故障进行了排查复盘,发出故障公告如下:
> 5月31号中午12点17分起,阿里云侧serverless因异常流量飙高,集群内部带宽负载超限,导致部分请求超时或变慢。阿里云工程师通过异常流量治理、扩容,在15点左右将系统恢复到正常状态。针对此次暴露风险,阿里云内部会继续做流量隔离、切换弹性链路、异常流量熔断等方案,确保此类问题不会再次发生。
针对此次故障,DCloud一方面积极推动阿里云按照SLA协议执行相关赔付,目前达成的赔付方案如下:
- 因5月31日故障,影响的主要是云函数和云数据库资源,经协商,所有开发者在5月31日消耗的云函数和云数据库资源,折算金额后,阿里云全额返还给开发者;
- DCloud会帮助落实退费措施,将对应金额充值到开发者的uniCloud阿里云余额下,该项退费工作预计在本周(2023年6月10)前完成;特别说明:如果您之前仅有包月套餐的空间,我们也会计算5月31日费用,并退还到您账号下的阿里云余额中,后续您购买按量计费套餐时,可以直接使用该笔余额。
另一方面,DCloud会继续催促阿里云切实落实资源隔离措施,确保服务的健壮稳定。
5月31日,部分开发者反应阿里云版云函数响应缓慢,DCloud紧急联系阿里云快速治理恢复,详见https://ask.dcloud.net.cn/question/170939。
业务恢复后,阿里云内部也对故障进行了排查复盘,发出故障公告如下:
> 5月31号中午12点17分起,阿里云侧serverless因异常流量飙高,集群内部带宽负载超限,导致部分请求超时或变慢。阿里云工程师通过异常流量治理、扩容,在15点左右将系统恢复到正常状态。针对此次暴露风险,阿里云内部会继续做流量隔离、切换弹性链路、异常流量熔断等方案,确保此类问题不会再次发生。
针对此次故障,DCloud一方面积极推动阿里云按照SLA协议执行相关赔付,目前达成的赔付方案如下:
- 因5月31日故障,影响的主要是云函数和云数据库资源,经协商,所有开发者在5月31日消耗的云函数和云数据库资源,折算金额后,阿里云全额返还给开发者;
- DCloud会帮助落实退费措施,将对应金额充值到开发者的uniCloud阿里云余额下,该项退费工作预计在本周(2023年6月10)前完成;特别说明:如果您之前仅有包月套餐的空间,我们也会计算5月31日费用,并退还到您账号下的阿里云余额中,后续您购买按量计费套餐时,可以直接使用该笔余额。
另一方面,DCloud会继续催促阿里云切实落实资源隔离措施,确保服务的健壮稳定。
收起阅读 »
小程序全局挂载Vue.prototype,在页面中无法读取
let mpdata = {a:'a',b:'b'}
Vue.prototype.mpdata = mpdata;
index.vue
{{mpdata.a}} 会是undefined
解决方案:
let mpdata = {a:'a',b:'b'}
Vue.prototype.mpdata = ()=>mpdata;
{{mpdata().a}}
把变量放到方法中
let mpdata = {a:'a',b:'b'}
Vue.prototype.mpdata = mpdata;
index.vue
{{mpdata.a}} 会是undefined
解决方案:
let mpdata = {a:'a',b:'b'}
Vue.prototype.mpdata = ()=>mpdata;
{{mpdata().a}}
把变量放到方法中
收起阅读 »
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页面突起图标加跳转