UNPKG

vc-popup

Version:

vue popup components with power position and animation support and back key support as well

373 lines (324 loc) 12.1 kB
import popupController from './index' let popupBase = { open: function (e, runtimeConfig = {}) { if (this.vmBase && this.vmBase.isShowing) return console.log('已经open调用了, 需要close之后再调用, 不过可以多次new') var routerId = this.getRouterId() // 配置初始化 this.config = Object.assign({ animation: {}, lockScroll: true, positionType: 'absolute' }, this.constructConfig, runtimeConfig) this.config.propsData = Object.assign( {}, this.constructConfig.propsData, runtimeConfig.propsData) this.config.propsData.e = e // dom节点初始化 this.vmBase = popupController.createPopup( this.popupConfig, this.config, routerId) this.vmBase.vmSlot = this.vmSlot = new this.Template({ el: this.vmBase.$refs.slot, propsData: this.config.propsData }) this.vmBase.$refs.slot = this.vmSlot.$el this.vmSlot.$popupCtrl = this this.vmSlot.popupEvt = this.vmSlot.popupEvt || {} popupController.register(routerId, this.open.bind(this, e, runtimeConfig)) popupController.open(this.vmBase, routerId) }, close: function () { if (this.vmBase.isShowing) { this.vmBase.isShowing = false history.back() } }, configPosition: function (e) { var config = this.config var $slotContainer = this.vmBase.$refs.slotContainer var $slot = $slotContainer.children[0] var position = config.position // 公用 var fromLeft, fromTop, originX, originY var fromFrameLeft, fromFrameTop var placeLeftOffset, placeRightOffset, placeBottomOffset, placeTopOffset var margins = [] var frame = {} var dWidth = $slot.clientWidth var dHeight = $slot.clientHeight // clickRelative 需要的 var clickX, clickY // domRelative 需要的 var $refDom, refRect var refCorner, relativeToCorner this.vmBase.positionType = config.positionType if (config.positionType === 'absolute') { $slotContainer.style.webkitTransform = `translate(${window.scrollX}px, ${window.scrollY}px)` } if (position === 'center' || position === undefined) { position = {} } if (position instanceof Object) { frame.width = window.innerWidth frame.height = window.innerHeight var helper = function (one, another) { var tmp var frameOne = one === 'top' ? frame.height : frame.width var dOne = one === 'top' ? dHeight : dWidth one = position[one] another = position[another] if (one !== undefined) { // 百分比处理 if (typeof one === 'string' && one.indexOf('%') !== -1) { tmp = parseFloat(one.slice(0, one.indexOf('%'))) * frameOne } else if (typeof one === 'string' || typeof one === 'number') { tmp = one } else { console.log('position.top的参数类型不对~') } } else if (another !== undefined) { // 百分比处理 if (typeof another === 'string' && another.indexOf('%') !== -1) { tmp = (1 - parseFloat(another.slice(0, another.indexOf('%')))) * frameOne } else if (typeof another === 'string' || typeof another === 'number') { tmp = frameOne - parseFloat(another) - dOne } else { console.log('position.bottom的参数类型不对~') } } else { // 居中 tmp = (frameOne - dOne) / 2 } return tmp } fromTop = helper('top', 'bottom') fromLeft = helper('left', 'right') $slot.style.marginLeft = fromLeft + 'px' $slot.style.marginTop = fromTop + 'px' } if (position === 'clickRelative') { // region 点击坐标初始化 if (e === undefined) return if (e.touches && e.touches[0]) { clickX = e.touches[0].clientX clickY = e.touches[0].clientY } else if (e.clientX) { clickX = e.clientX clickY = e.clientY } // endregion // region 外框 格式化 TODO 之后可以缓存这个,不过动态也是有好处的, 性能优化的时候在做吧 if (config.frame instanceof Object) { frame.top = config.frame.top frame.left = config.frame.left frame.width = config.frame.width frame.height = config.frame.height } else if (config.frame instanceof HTMLElement) { var rect = config.frame.getBoundingClientRect() frame.top = rect.top frame.left = rect.left frame.width = rect.width frame.height = rect.height } else { frame.top = 0 frame.left = 0 frame.width = window.innerWidth frame.height = window.innerHeight } // endregion // region margin 导入 if (typeof config.margin === 'number' || typeof config.margin === 'string') { margins[0] = margins[1] = margins[2] = margins[3] = config.margin } else if (config.margin instanceof Array) { if (config.margin.length === 2) { margins[0] = margins[2] = config.margins[0] margins[1] = margins[3] = config.margins[1] } else if (config.margin.length === 4) { margins[0] = config.margins[0] margins[1] = config.margins[1] margins[2] = config.margins[2] margins[3] = config.margins[3] } } else { margins[0] = margins[1] = margins[2] = margins[3] = 0 } // margin 数值格式化 var formatValue = function (val, base) { if (typeof val === 'string') { if (val[val.length - 1] === '%') { return parseInt(val.slice(0, val.length - 1)) * base } else if (val.indexOf('px') !== -1) { return parseInt(val.replace('px', '')) } } else if (typeof val === 'number') { return val } } margins[0] = formatValue(margins[0], frame.height) margins[1] = formatValue(margins[1], frame.width) margins[2] = formatValue(margins[2], frame.height) margins[3] = formatValue(margins[3], frame.width) //endregion fromFrameLeft = clickX - frame.left fromFrameTop = clickY - frame.top //region 左右 // 假设放在左右边的情况 placeLeftOffset = frame.width - fromFrameLeft - dWidth - margins[1] placeRightOffset = fromFrameLeft - dWidth - margins[3] if (dWidth < frame.width) { if (placeLeftOffset < 0) { if (placeRightOffset > 0) { fromLeft = clickX - dWidth originX = 'right' } else { if (placeLeftOffset > placeRightOffset) { fromLeft = clickX + placeLeftOffset originX = 'left' } else { fromLeft = clickX - dWidth - placeRightOffset originX = 'left' } } } else { // 右边可以嵌入正常 fromLeft = clickX originX = 'left' } } else { // 溢出的情况 fromLeft = 0 originX = 'left' } // endregion // region 上下 // 假设放在上下边的情况 placeBottomOffset = frame.height - fromFrameTop - dHeight - margins[2] placeTopOffset = fromFrameTop - dHeight - margins[0] if (dHeight < frame.height) { if (placeBottomOffset < 0) { if (placeTopOffset > 0) { fromTop = clickY - dHeight originY = 'bottom' } else { if (placeBottomOffset > placeTopOffset) { fromTop = clickY + placeBottomOffset originY = 'top' } else { fromTop = clickY - dHeight - placeTopOffset originY = 'bottom' } } } else { // 右边可以嵌入正常 fromTop = clickY originY = 'top' } } else { // 溢出的情况 fromTop = 0 originY = 'top' } // endregion $slot.style.position = 'absolute' $slot.style.left = fromLeft + 'px' $slot.style.top = fromTop + 'px' } // region if (position === 'domRelative' && config.refDom instanceof HTMLElement) { $refDom = config.refDom refRect = $refDom.getBoundingClientRect() //解析参数 refCorner = this.parseRefCorner(config.refCorner) relativeToCorner = this.parseRelativeToCorner(config.relativeToCorner) // 设定位置 fromLeft = refRect.left fromTop = refRect.top if (refCorner[0] === 'bottom') { fromTop += refRect.height } else if (refCorner[0] === 'center') { fromTop += refRect.height / 2 - dHeight / 2 } if (refCorner[1] === 'right') { fromLeft += refRect.width } else if (refCorner[1] === 'center') { fromLeft += refRect.width / 2 - dWidth / 2 } if (relativeToCorner[0] === 'above' && refCorner[0] !== 'center') { fromTop -= dHeight } if (relativeToCorner[1] === 'before' && refCorner[1] !== 'center') { fromLeft -= dWidth } originY = refCorner[0] !== 'center' ? relativeToCorner[0] === 'above' ? 'bottom' : 'top' : 'center' originX = refCorner[1] !== 'center' ? relativeToCorner[1] === 'before' ? 'right' : 'left' : 'center' $slot.style.position = 'absolute' $slot.style.left = fromLeft + 'px' $slot.style.top = fromTop + 'px' } // endregion // 设置动画重心 if (config.autoSetOrthocenter === true) { $slot.style['transform-origin'] = (originY + ' ' + originX) } }, getRouterId: function () { if (this.config.name === undefined) { return this.name + '_' + popupController.popupInShowingNum } else if (typeof this.config.name === 'string' && this.config.name !== '') { return this.config.name } else { console.log('出现不合法的routerId~') return null } }, parseRefCorner: function (cRefCorner) { // 解析refCorner var refCorner var validVerticalRefCorner = ['top', 'bottom', 'center'] var validHorizonalRefCorner = ['left', 'right', 'center'] if (cRefCorner === undefined) { // 缺省默认 refCorner = ['top', 'right'] } else if (typeof cRefCorner === 'string') { refCorner = cRefCorner.split(' ') // 检查参数是否合法 if ( refCorner.length !== 2 || !validVerticalRefCorner.includes(refCorner[0]) || !validHorizonalRefCorner.includes(refCorner[1]) ) { console.log('refCorner配置有误~') } } else { // 非法参数,或者不可解析的参数 console.log('refCorner配置有误~') } return refCorner }, parseRelativeToCorner: function (cRelativeToCorner) { // 解析refCorner var relativeToCorner var validVerticalRelativeToCorner = ['below', 'above'] var validHorizonalRelativeToCorner = ['before', 'after'] // 解析relativeToCorner if (cRelativeToCorner === undefined) { // 缺省默认 relativeToCorner = ['below', 'after'] } else if (typeof cRelativeToCorner === 'string') { relativeToCorner = cRelativeToCorner.split(' ') // 检查参数是否合法 if ( relativeToCorner.length !== 2 || !validVerticalRelativeToCorner.includes(relativeToCorner[0]) || !validHorizonalRelativeToCorner.includes(relativeToCorner[1]) ) { console.log('relativeToCorner配置有误~') } } else { // 非法参数,或者不可解析的参数 console.log('relativeToCorner配置有误~') } return relativeToCorner } } export default popupBase