【uniapp-小程序】实现方法调用的全局tips弹窗
【uniapp-小程序】实现方法调用的全局tips弹窗
- 开发背景
- 弹窗组件
- 全局调用
- 封装配置项入参
- 全局注入
- 使用
- 附带:如何在uniapp-H5项目中实现全局自定义弹窗
- 组件定义
- 定义vue插件
- 引入
笑死,只有在想找工作的时候才会想更新博客。
开发背景
本来是个uniapp开发的H5项目,但是由于上面要求需要转为小程序版本,导致很多原先支持的功能都需要针对小程序环境进行兼容。这次先说说自定义的全局提示弹窗。代码中使用了较多uniapp组件,详细使用方法请查看uniapp官方文档
框架:uniapp、小程序、vue2
弹窗组件
弹窗组件其实就是个常规的vue页面,通过设置蒙层+层级实现弹窗效果,实现简单,可扩展性强。
- 样式中使用了import语法是为了覆盖uniapp原生样式,如不需要可去除;
safeAreaTop
为自定义字段,为获取的小程序顶部状态栏高度;- 弹窗内容显示使用了uniapp的
rich-text
组件,如对弹窗内容显示要求没那么高的可以直接展示文本,如:<text decode>{{content}}</text>
,其中decode是为了实现换行; - 很多配置项是为了满足我项目的需求,并非必须,可按需调整。
<template>
<view class="confirm-modal" v-if="visible" :style="{top:`${safeAreaTop}px`}">
<view class="confirm-modal-mask flex justify-center align-center">
<view class="confirm-modal-content" :style="contentStyle">
<view class="close-top-btn flex justify-end align-center" v-if="closeEnabled">
<uni-icons type="closeempty" size=20 color="#999" @click="handleClose"></uni-icons>
</view>
<view class="title flex justify-center align-center" v-if="title">
{{title}}
</view>
<view :style="{marginTop: closeEnabled&&!title?'24px':0}"
class="flex justify-center align-center text-center">
<rich-text :nodes="content"></rich-text>
</view>
<view class="flex justify-between align-center operation">
<button type="primary" :plain="cancelClassName.indexOf('cancel')>-1" v-if="showCancel" @click="handleClose" class="round" :class="cancelClassName">
{{cancelText}}
</button>
<button type="primary" :plain="confirmClassName.indexOf('cancel')>-1" v-if="showConfirm" @click="handleOk" class="round" :class="confirmClassName">
{{confirmText}}
</button>
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapGetters
} from 'vuex'
export default {
data() {
return {
safeAreaTop: this.$safeAreaTop, // 获取小程序顶部状态栏高度,按需使用
}
},
computed: {
...mapGetters(['confirmModal']),
title() {
return this.confirmModal.title
},
content() {
return this.confirmModal.content
},
// 默认:default, 整行: block
btnType() {
return this.confirmModal.btnType || 'default'
},
cancelText() {
return this.confirmModal.cancelText || '取消'
},
confirmText() {
return this.confirmModal.confirmText || '确定'
},
cancelClass() {
return this.confirmModal.cancelClass
},
confirmClass() {
return this.confirmModal.confirmClass
},
showCancel() {
return typeof this.confirmModal.showCancel === 'boolean' ? this.confirmModal.showCancel : true
},
showConfirm() {
return typeof this.confirmModal.showConfirm === 'boolean' ? this.confirmModal.showConfirm : true
},
visible() {
return typeof this.confirmModal.visible === 'boolean' ? this.confirmModal.visible : false
},
success() {
return this.confirmModal.success
},
cancel() {
return this.confirmModal.cancel
},
closeEnabled() {
return typeof this.confirmModal.closeEnabled === 'boolean' ? this.confirmModal.closeEnabled : false
},
contentStyle() {
return this.confirmModal.contentStyle
},
cancelClassName() {
if (this.cancelClass !== '') {
return this.cancelClass
}
if (this.btnType === 'block') {
return 'cancel-btn-block'
}
return 'cancel-btn'
},
confirmClassName() {
if (this.confirmClass !== '') {
return this.confirmClass
}
if (this.btnType === 'block') {
return 'confirm-btn-block'
}
return 'confirm-btn'
}
},
beforeDestroy() {
if (this.visible) {
this.$store.commit('SET_CONFIG', {
visible: false
})
}
},
methods: {
handleClose() {
if (typeof this.cancel === 'function') {
this.cancel()
}
this.$store.commit('SET_CONFIG', {
visible: false
})
},
handleOk() {
if (typeof this.success === 'function') {
this.success()
}
this.$store.commit('SET_CONFIG', {
visible: false
})
}
}
}
</script>
<style lang="scss" scoped>
.confirm-modal {
height: 100%;
width: 100%;
overflow: hidden;
z-index: 12;
position: absolute;
top: 0;
left: 0;
.confirm-modal-mask {
background-color: rgba(0, 0, 0, 0.6);
width: 100%;
height: 100%;
.confirm-modal-content {
background-color: #fff;
border-radius: 6px;
width: 85%;
padding: 24px;
position: relative;
.title {
font-weight: bold;
margin: 8px 0 12px 0;
font-size: 32rpx;
}
.close-top-btn {
position: absolute;
right: 12px;
top: 12px;
}
.operation {
width: 100%;
background-color: #fff;
flex-wrap: wrap;
.round {
margin-top: 24px;
}
.cancel-btn{
border-color:#00AEB8 !important;
color:#00AEB8 !important;
width: 45%;
font-size: 30rpx;
white-space: nowrap;
}
.confirm-btn{
background-color: #00AEB8 !important;
width: 45%;
font-size: 30rpx;
white-space: nowrap;
}
.cancel-btn-block{
border-color:#00AEB8 !important;
color:#00AEB8 !important;
width: 100%;
font-size: 30rpx;
white-space: nowrap;
}
.confirm-btn-block{
background-color: #00AEB8 !important;
width: 100%;
font-size: 30rpx;
white-space: nowrap;
}
}
}
}
}
</style>
弹窗效果如下所示:
全局调用
当我们写好弹窗组件时,就可以在需要的页面内引入调用(以上代码中各配置项的输入需更改为props传入,或通过ref绑定组件,调用组件内方法传入)。但是每次使用都得引入、调用,过于繁琐。为了方便使用,可以封装为全局引入,并在需要的页面内通过方法调用,实现方案如下:
封装配置项入参
在store内定义一个modules用来存储弹窗配置项并在getters内声明(按需):
const confirmModal = {
state: {
config: {
title: '',
content: '',
btnType: 'default',
cancelText: '取消',
confirmText: '确定',
cancelClass: '',
confirmClass: '',
showCancel: true,
showConfirm: true,
visible: false,
success: null,
cancel: null,
closeEnabled: false,
contentStyle: '',
}
},
mutations: {
SET_CONFIG: (state, config) => {
const defaultConfig = {
content: '',
btnType: 'default',
cancelText: '取消',
confirmText: '确定',
cancelClass: '',
confirmClass: '',
showCancel: true,
showConfirm: true,
visible: true,
success: null,
cancel: null,
title: '',
closeEnabled: false,
contentStyle: ''
}
if (typeof config === 'string') {
state.config = Object.assign(defaultConfig, {
content: options
});
} else if (typeof config === 'object') {
state.config = Object.assign(defaultConfig, config);
}
}
}
}
export default confirmModal
组件内的参数从store获取,想要显示弹窗时调用this.$store.commit('SET_CONFIG', {})
,第二个参数为弹窗配置内容。
全局注入
在main.js文件内注入组件:
// 引入组件,请根据自己定义组件的实际路径和名称引入
import ConfirmModal from './components/confirm-modal/confirm-modal.vue'
Vue.component('confirm-modal', ConfirmModal)
// 每次都通过$store调用过于繁琐,所以定义了一个全局方法
Vue.prototype.$confirmModal = (config) => {
store.commit('SET_CONFIG', config)
}
// 获取小程序顶部状态栏高度
const {
safeArea
} = wx.getWindowInfo()
Vue.prototype.$safeAreaTop = safeArea && safeArea.top || 0
使用
this.$confirmModal({
content: '请确认是否删除该条跟发规则?',
cancelText: '取消',
confirmText: '确认',
success: () => {}
})
调用后,效果如上图
附带:如何在uniapp-H5项目中实现全局自定义弹窗
组件定义
组件的基本内容不变,主要是将弹窗配置项作为props转入,如下:
定义vue插件
在组件目录下定义index.js文件:
import Vue from 'vue'
import confirmModalVue from './confirm-modal.vue';
// 定义插件对象
const confirmModal = {};
// vue的install方法,用于定义vue插件
confirmModal.install = function(Vue, options) {
const confirmModalInstance = Vue.extend(confirmModalVue);
let currentMsg;
const initInstance = () => {
// 实例化vue实例
currentMsg = new confirmModalInstance();
let msgBoxEl = currentMsg.$mount().$el;
document.body.appendChild(msgBoxEl);
};
// 在Vue的原型上添加实例方法,以全局调用
Vue.prototype.$confirmModal = (options) => {
if (!currentMsg) {
initInstance();
}
const config = {
content: '',
btnType: 'default',
cancelText: '取消',
confirmText: '确定',
cancelClass: '',
confirmClass: '',
showCancel: true,
showConfirm: true,
visible: true,
success: null,
cancel: null,
title: '',
closeEnabled: false,
contentStyle: ''
}
if (typeof options === 'string') {
Object.assign(currentMsg, config, {
content: options
});
} else if (typeof options === 'object') {
Object.assign(currentMsg, config, options);
}
return currentMsg; // 为了链式调用
};
};
export default confirmModal;
引入
在main.js内引入:
import ConfirmModal from './components/confirm-modal'
Vue.use(ConfirmModal)