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
JavaScript
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