小程序wx.showModal二次封装

3,236 阅读3分钟

前言

该文是关于小程序弹框showModal的一个二次封装。用于记录、并与各位掘友交流。

建议阅读时间10-15分钟,欢迎交流。不对之处,请各位掘友不吝赐教与斧正。

封装前后对比

封装优缺点

1、减少每个弹框的调用重复配置项

2、调用方便,支持直接输入字符串作为提示语

3、本文提供的封装版本是:相同提示语只会弹框一次,不同提示语还是会弹框。

4、配置灵活,该弹框基础上,可修改为实现只弹一个弹框等功能

5、封装使用了Promise,这里额外封了一层,使调用更加多样。免得调用时一定要then()或者catch(),不然控制台看着飘红会uncomfortable

6、暂不支持使用editable功能

7、目前该版本做得比较简单。不同提示语多个弹框是同时出来的,导致弹框界面的背景过暗(多个遮罩,微信没有做处理)。在此基础上,可以进一步封装一个外部状态管理器,用于储存多个同时需要提示的弹框,next方法之后执行下一个弹框。这个后续看情况去写吧~

wx.showModal: 显示模态对话框

575e79810fab5f7b473d4a6b81055f6.png

官方实例代码:

wx.showModal({
  title: '提示',
  content: '这是一个模态弹窗',
    if (res.confirm) {
      console.log('用户点击确定')
    } else if (res.cancel) {
      console.log('用户点击取消')
    }
  }
})

封装代码

class ShowModal {
  options = {}      // 配置项
  lastOptions = {}  // 上一次的配置项

  constructor(options) {
    this.init(options)
  }
  init(options) {
    /**
     * @param {string || object} options 字符串或者对象。字符串时,提示内容就是options,title默认为“提示”
     */
    let optionsInit = {}
    if (typeof options === 'string') {
      optionsInit.msg = options
    } else if (options && typeof options === 'object' && !Array.isArray(options)) {
      optionsInit = options
    } else {
      throw new Error('The params is not a object or string')
    }
    this.setOptions(optionsInit)
  }
  setOptions({
    msg = '',
    title = '提示',
    showCancel = true,
    confirmColor = '#68C646',
    cancelColor = '#333333',
    confirmText = '确定',
    cancelText = '取消'
  } = {}) {
    this.options = {
      title,
      content: msg,
      showCancel,
      confirmColor,
      cancelColor,
      confirmText,
      cancelText
    }
  }
  show() {
    return new Promise((resolve, reject) => {
      if (this.lastOptions.content === this.options.content) {
        // 屏蔽相同提示语弹框。但callback会直接执行该重复弹框的confirmCallBack
        return resolve()
      }
      this.lastOptions = this.options
      uni.showModal({
        ...this.options,
        success: function(res) {
          if (res.confirm) {
            resolve()
          } else if (res.cancel) {
            reject()
          }
        },
        fail: () => {
          reject()
        },
        complete: () => {
          // 完成后要清除lastOptions,免得点击相同提示框时,第二次不再生效
          this.lastOptions = {}
        }
      })
    })
  }
}

以下可放在同一文件,也可分开

const createShowModal = (function() {
  // 创建单例
  let modal
  return function(options) {
    if (modal) {
      modal.init(options)
    } else {
      modal = new ShowModal(options)
    }
    return modal
  }
})()

class Modal {
  // 自定义then, catch, finally,这样就不一定在调用时写then() 或者catch()。否则控制台飘红
  confirmCallBack = null
  cancelCallBack = null
  finallyCallBack = null
  init(options) {
    this.modal = createShowModal(options)
  }
  isFunc(fn) {
    return typeof fn === 'function'
  }
  show() {
    this.modal.show().then(() => {
      typeof this.confirmCallBack === 'function' && this.confirmCallBack()
      this.clean()
    }).catch(() => {
      typeof this.cancelCallBack === 'function' && this.cancelCallBack()
      this.clean()
    }).finally(() => {
      typeof this.finallyCallBack === 'function' && this.finallyCallBack()
      this.clean()
    })
  }
  clean() {
    // 主动释放内存。当然,小程序也有自己的回收机制
    this.confirmCallBack = null
    this.cancelCallBack = null
    this.finallyCallBac = null
  }
  then(fn) {
    // 设置Modal右边按钮回调
    if (!this.isFunc(fn)) {
      throw new Error(JSON.stringify(fn) + ' is not a function')
    }
    this.confirmCallBack = fn
    return this
    // return entryModal()
  }
  catch(fn) {
    // 设置Modal左边按钮回调
    if (!this.isFunc(fn)) {
      throw new Error(JSON.stringify(fn) + ' is not a function')
    }
    this.cancelCallBack = fn
    return this
    // return entryModal()
  }
  finally(fn) {
    if (!this.isFunc(fn)) {
      throw new Error(JSON.stringify(fn) + ' is not a function')
    }
    this.finallyCallBack = fn
    return this
  }
}

// const entryModal = (function() {
//   // 只设置一个弹框的话可以使用这个,在这个基础上去改。可能还需要配合一个外部的状态管理器
//   let modalBox = null
//   return function() {
//     // 创建唯一并初始化Modal弹框
//     if (!modalBox) {
//       modalBox = new Modal()
//     }
//     return modalBox
//   }
// })()

const modal = function(options) {
  // const modalBox = entryModal()
  const modalBox = new Modal()
  modalBox.init(options)
  modalBox.show()
  return modalBox
}
export default modal

使用说明

引入文件,这边用的例子是uniapp

main.js文件

import Modal from '@/utils/Modal'
Vue.prototype.Modal = Modal

具体页面调用示例:

    1. this.Modal('提示内容')
    1. this.Modal({ title: '提示标题', msg: '提示内容' })
    1. this.Modal(options).then(() => {}) // 点击确认回调(右边按钮)
    1. this.Modal(options).catch(() => {}) // 点击取消回调(左边按钮)
    1. this.Modal(options).then(() => {}).catch(() => {}) // 同时有确认和取消的回调
测试下

0005ae206541818806dc3ccbf383422.png

调用四次,共会弹出3个框:

bc430301b0157fc47d421c05cae3163.png

cedeb49d12bfb652084df3e095fee95.png

dfd2217f015196231022adfb09a2c66.png

点击确定时控制台分别输出:

1.1(不会弹框,自动输出)

2(第一个弹框,点击确定输出)

1(第二个弹框,点击确定输出)

0(第三个弹框,点击确定输出)

结语

以上是关于本次showModal的分享,谢谢各位亲的阅读。写得还比较浅,欢迎交流,顺便能给个赞支持一下最好了,毕竟第一次写(^▽^)。