components/indicator/indicator.js

/**
 * Created by Hsiang on 2017/4/24.
 */

/**
 * @component Indicator
 * @description
 *
 * ## 弹出层 / Indicator组件(小Loading)
 *
 * Indicator组件调用不需要传入参数, 只需要在不需要他的时候调用`dismiss()`方法即可, 他的默认最大开启时间为10000ms. 这部分可在config中通过`maxIndicatorDuration`配置.
 *
 * ### 关于时间的说明
 *
 * - Indicator最短开启时间(indicatorPresentMinTime), 一般是328ms, 这部分可在config中通过`indicatorPresentMinTime`配置
 * - Indicator开启的最大时间(indicatorMaxDuration), 一般是5000ms, 这部分可在config中通过`indicatorMaxDuration`配置
 *
 * @see component:Loading
 *
 * @props {Object} options - 参数
 * @props {Boolean} [isReverse=false] - 是否反色
 * @props {Boolean} [dismissOnPageChange=true] - 页面切换是否关闭
 *
 * @demo #/indicator
 * @usage
 * // 开启300ms后关闭
 * openIndicator300 () {
 *      this.$indicator.present()
 *      setTimeout(() => {
 *        this.$indicator.dismiss()
 *      }, 300)
 * },
 *
 *
 * // 反色
 * openIndicator300 () {
 *      this.$indicator.present(true)
 *      setTimeout(() => {
 *        this.$indicator.dismiss()
 *      }, 300)
 * },
 *
 * */

import Vue from 'vue'
import getInsertPosition from '../../util/getInsertPosition'
import { isBlank, isBoolean, isObject, isString } from '../../util/util'
import loadingComponent from '../loading/loading.vue'

const Loading = Vue.extend(loadingComponent)
let debug = false

// -------- function --------

function LoadingFactory (options) {
  let el = getInsertPosition('loadingPortal').appendChild(
    document.createElement('div')
  )
  if (isString(options)) {
    options = { content: options }
  }
  return new Loading({ el, propsData: options })
}

export default {
  _i: null, // instance 组件实例
  _startTime: new Date().getTime(),
  _timer: 0,
  _count: 0,

  /**
   * 开启组件
   * @desc
   * 如果上一个实例是开启状态, 则自动关闭后开启新的
   * @param {Object|Boolean} options - isReverse
   * @param {Boolean} options.isReverse - 是否反色
   * @param {Boolean} options.dismissOnPageChange - 页面切换是否关闭
   * */
  present (options) {
    debug && console.log('indicator.js present')

    let defaultOptions = {
      isReverse: false,
      dismissOnPageChange: false
    }

    if (isBlank(options)) {
      options = defaultOptions
    }

    if (isObject(options)) {
      options = Object.assign({}, defaultOptions, options)
    }

    if (isBoolean(options)) {
      options = {
        isReverse: options,
        dismissOnPageChange: false
      }
    }

    return new Promise(resolve => {
      if (!this._i) {
        // 当前没人在场
        debug && console.debug('Indicator 1 当前没人在场: 未开启状态, 准备开启')
        this._startTime = new Date().getTime()
        let cssClass = 'indicator'
        if (options.isReverse) {
          cssClass += ' reverse'
        }
        const Duration =
          window.VM &&
          window.VM.config &&
          window.VM.config.getNumber('indicatorMaxDuration', 5000) // 多少分
        this._i = LoadingFactory({
          cssClass: cssClass,
          showBackdrop: false,
          duration: Duration, // 以防万一
          dismissOnPageChange: options.dismissOnPageChange,
          mode: 'ios'
        })
        this._i.present().then(() => {
          resolve()
        })
      } else {
        // 当前有人在场
        if (this._i.isActive) {
          debug && console.debug('Indicator 2 当前有人在场: 状态开启中')
          // 在场表演呢
          if (this._timer) {
            // 存在定时器要她退场
            debug && console.debug('Indicator 3 存在定时器要她退场: 这里清除定时器')
            this._timer && window.clearTimeout(this._timer)
            this._timer = 0
          } else {
            this._count++
            debug &&
              console.debug('Indicator 4 当前有人在场, 投票++ _count: ' + this._count)
          }
          resolve()
        } else {
          // 当前正在退场
          debug && console.debug('Indicator 5 当前正在退场: 不管他, 我这里执行一次开启')
          // this._i.isActive = true
          this._i.present().then(() => {
            resolve()
          })
        }
      }
    })
  },

  /**
   * 关闭组件
   * @return {Promise} - 关闭动画结束的promise
   * */
  dismiss () {
    debug && console.log('indicator.js dismiss')
    return new Promise(resolve => {
      if (this._i) {
        // 实例存在
        debug && console.debug('Indicator 11: 实例存在')
        if (this._count > 0) {
          // 要求多次开启, 关闭时减一票
          this._count--
          debug &&
            console.debug(
              'Indicator 12: 要求多次开启, 关闭时减一票, 当前count有值: ' + this._count
            )
        } else {
          if (this._i.isActive) {
            // active状态
            debug && console.debug('Indicator 13: 组件是active状态: 正常关闭')

            if (this._timer) {
              debug && console.debug('Indicator 14: 有定时器关闭: 这里不处理')
            } else {
              let now = new Date().getTime()
              let diff = now - this._startTime
              const MinTime =
                window.VM &&
                window.VM.config &&
                window.VM.config.getNumber(
                  'indicatorPresentMinTime',
                  200 + 16 * 8
                ) // Indicator最短开启时间
              if (diff >= MinTime) {
                // 满足在场的最短时间, 可以关闭, 重置初始状态
                debug && console.debug('Indicator 15: 超过300ms 正常关闭')
                this._i.dismiss().then(() => {
                  this._i = null
                  this._startTime = null
                  this._timer && window.clearTimeout(this._timer)
                  this._timer = 0
                  this._count = 0
                  resolve()
                })
              } else {
                // 不满足在场的最短时间, 保证300ms, 剩余时间定时补足
                let rest = MinTime - diff
                debug &&
                  console.debug(
                    `Indicator 16: 为了保证${MinTime}ms后关闭, 这里进行定时, 剩余关闭时间: ${rest}, MinTime: ${MinTime}, diff: ${diff}`
                  )
                this._timer = window.setTimeout(() => {
                  this._i.dismiss().then(() => {
                    this._i = null
                    this._startTime = null
                    this._timer && window.clearTimeout(this._timer)
                    this._timer = 0
                    this._count = 0
                    resolve()
                    debug && console.debug(`Indicator 16-resolve`)
                  })
                }, rest)
              }
            }
          } else {
            // 退场状态(已经在退场了, 这里不作处理)
            debug && console.debug('Indicator 17: 退场状态(已经在退场了, 这里不作处理)')
            this._i = null
            this._startTime = null
            this._timer && window.clearTimeout(this._timer)
            this._timer = 0
            this._count = 0
            resolve()
          }
        }
      } else {
        // 实例不存在(不存在不需要退场)
        debug && console.debug('Indicator 18: 实例不存在(不存在不需要退场)')
        this._i = null
        this._startTime = null
        this._timer && window.clearTimeout(this._timer)
        this._timer = 0
        this._count = 0
        resolve()
      }
    })
  }
}