vxe-table-select-area
Version:
一个基于 vxe-table 的可区域选中复制、粘贴的组件
259 lines (257 loc) • 8.04 kB
JavaScript
import GlobalConfig from '../../v-x-e-table/src/conf'
import vSize from '../../mixins/size'
import UtilTools from '../../tools/utils'
import DomTools from '../../tools/dom'
import { GlobalEvent } from '../../tools/event'
export default {
name: 'VxePulldown',
mixins: [vSize],
props: {
value: Boolean,
disabled: Boolean,
placement: String,
size: { type: String, default: () => GlobalConfig.size },
destroyOnClose: Boolean,
transfer: Boolean
},
data () {
return {
inited: false,
panelIndex: 0,
panelStyle: null,
panelPlacement: null,
currentValue: null,
visiblePanel: false,
animatVisible: false,
isActivated: false
}
},
watch: {
value (value) {
if (value) {
this.showPanel()
} else {
this.hidePanel()
}
}
},
created () {
GlobalEvent.on(this, 'mousewheel', this.handleGlobalMousewheelEvent)
GlobalEvent.on(this, 'mousedown', this.handleGlobalMousedownEvent)
GlobalEvent.on(this, 'blur', this.handleGlobalBlurEvent)
},
beforeDestroy () {
const panelElem = this.$refs.panel
if (panelElem && panelElem.parentNode) {
panelElem.parentNode.removeChild(panelElem)
}
},
destroyed () {
GlobalEvent.off(this, 'mousewheel')
GlobalEvent.off(this, 'mousedown')
GlobalEvent.off(this, 'blur')
},
render (h) {
const { $scopedSlots, inited, vSize, destroyOnClose, transfer, isActivated, disabled, animatVisible, visiblePanel, panelStyle, panelPlacement } = this
const defaultSlot = $scopedSlots.default
const downSlot = $scopedSlots.dropdown
return h('div', {
class: ['vxe-pulldown', {
[`size--${vSize}`]: vSize,
'is--visivle': visiblePanel,
'is--disabled': disabled,
'is--active': isActivated
}]
}, [
h('div', {
ref: 'content',
class: 'vxe-pulldown--content'
}, defaultSlot ? defaultSlot.call(this, { $pulldown: this }, h) : []),
h('div', {
ref: 'panel',
class: ['vxe-table--ignore-clear vxe-pulldown--panel', {
[`size--${vSize}`]: vSize,
'is--transfer': transfer,
'animat--leave': animatVisible,
'animat--enter': visiblePanel
}],
attrs: {
placement: panelPlacement
},
style: panelStyle
}, downSlot ? [
h('div', {
class: 'vxe-pulldown--wrapper'
}, !inited || (destroyOnClose && !visiblePanel && !animatVisible) ? [] : downSlot.call(this, { $pulldown: this }, h))
] : [])
])
},
methods: {
handleGlobalMousewheelEvent (evnt) {
const { $refs, disabled, visiblePanel } = this
if (!disabled) {
if (visiblePanel) {
if (DomTools.getEventTargetNode(evnt, $refs.panel).flag) {
this.updatePlacement()
} else {
this.hidePanel()
this.$emit('hide-panel', { $event: evnt })
}
}
}
},
handleGlobalMousedownEvent (evnt) {
const { $refs, $el, disabled, visiblePanel } = this
if (!disabled) {
this.isActivated = DomTools.getEventTargetNode(evnt, $el).flag || DomTools.getEventTargetNode(evnt, $refs.panel).flag
if (visiblePanel && !this.isActivated) {
this.hidePanel()
this.$emit('hide-panel', { $event: evnt })
}
}
},
handleGlobalBlurEvent (evnt) {
if (this.visiblePanel) {
this.isActivated = false
this.hidePanel()
this.$emit('hide-panel', { $event: evnt })
}
},
updateZindex () {
if (this.panelIndex < UtilTools.getLastZIndex()) {
this.panelIndex = UtilTools.nextZIndex()
}
},
isPanelVisible () {
return this.visiblePanel
},
/**
* 切换下拉面板
*/
togglePanel () {
if (this.visiblePanel) {
return this.hidePanel()
}
return this.showPanel()
},
/**
* 显示下拉面板
*/
showPanel () {
if (!this.inited) {
this.inited = true
if (this.transfer) {
document.body.appendChild(this.$refs.panel)
}
}
return new Promise(resolve => {
if (!this.disabled) {
clearTimeout(this.hidePanelTimeout)
this.isActivated = true
this.animatVisible = true
setTimeout(() => {
this.visiblePanel = true
this.$emit('update:input', true)
this.updatePlacement()
setTimeout(() => {
resolve(this.updatePlacement())
}, 40)
}, 10)
this.updateZindex()
} else {
resolve(this.$nextTick())
}
})
},
/**
* 隐藏下拉面板
*/
hidePanel () {
this.visiblePanel = false
this.$emit('update:input', false)
return new Promise(resolve => {
if (this.animatVisible) {
this.hidePanelTimeout = setTimeout(() => {
this.animatVisible = false
resolve(this.$nextTick())
}, 350)
} else {
resolve(this.$nextTick())
}
})
},
/**
* 手动更新位置
*/
updatePlacement () {
return this.$nextTick().then(() => {
const { $refs, transfer, placement, panelIndex, visiblePanel } = this
if (visiblePanel) {
const panelElem = $refs.panel
const targetElem = $refs.content
if (panelElem && targetElem) {
const targetHeight = targetElem.offsetHeight
const targetWidth = targetElem.offsetWidth
const panelHeight = panelElem.offsetHeight
const panelWidth = panelElem.offsetWidth
const marginSize = 5
const panelStyle = {
zIndex: panelIndex
}
const { boundingTop, boundingLeft, visibleHeight, visibleWidth } = DomTools.getAbsolutePos(targetElem)
let panelPlacement = 'bottom'
if (transfer) {
let left = boundingLeft
let top = boundingTop + targetHeight
if (placement === 'top') {
panelPlacement = 'top'
top = boundingTop - panelHeight
} else if (!placement) {
// 如果下面不够放,则向上
if (top + panelHeight + marginSize > visibleHeight) {
panelPlacement = 'top'
top = boundingTop - panelHeight
}
// 如果上面不够放,则向下(优先)
if (top < marginSize) {
panelPlacement = 'bottom'
top = boundingTop + targetHeight
}
}
// 如果溢出右边
if (left + panelWidth + marginSize > visibleWidth) {
left -= left + panelWidth + marginSize - visibleWidth
}
// 如果溢出左边
if (left < marginSize) {
left = marginSize
}
Object.assign(panelStyle, {
left: `${left}px`,
top: `${top}px`,
minWidth: `${targetWidth}px`
})
} else {
if (placement === 'top') {
panelPlacement = 'top'
panelStyle.bottom = `${targetHeight}px`
} else if (!placement) {
// 如果下面不够放,则向上
if (boundingTop + targetHeight + panelHeight > visibleHeight) {
// 如果上面不够放,则向下(优先)
if (boundingTop - targetHeight - panelHeight > marginSize) {
panelPlacement = 'top'
panelStyle.bottom = `${targetHeight}px`
}
}
}
}
this.panelStyle = panelStyle
this.panelPlacement = panelPlacement
}
}
return this.$nextTick()
})
}
}
}