笑死,只有在想找工作的时间才会想更新博客。
开发背景
本来是个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)
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |