vxe-table-select-area
Version:
一个基于 vxe-table 的可区域选中复制、粘贴的组件
340 lines (338 loc) • 10.6 kB
JavaScript
import XEUtils from 'xe-utils'
import GlobalConfig from '../../v-x-e-table/src/conf'
import vSize from '../../mixins/size'
import UtilTools, { getFuncText } from '../../tools/utils'
import DomTools from '../../tools/dom'
import { GlobalEvent } from '../../tools/event'
export default {
name: 'VxeButton',
mixins: [vSize],
props: {
type: String,
size: { type: String, default: () => GlobalConfig.button.size || GlobalConfig.size },
name: [String, Number],
content: String,
placement: String,
status: String,
icon: String,
round: Boolean,
circle: Boolean,
disabled: Boolean,
loading: Boolean,
destroyOnClose: Boolean,
className: String,
transfer: { type: Boolean, default: () => GlobalConfig.button.transfer }
},
data () {
return {
inited: false,
showPanel: false,
animatVisible: false,
panelIndex: 0,
panelStyle: null,
panelPlacement: null
}
},
computed: {
isText () {
return this.type === 'text'
},
isFormBtn () {
return ['submit', 'reset', 'button'].indexOf(this.type) > -1
},
btnType () {
return this.isText ? this.type : 'button'
}
},
created () {
GlobalEvent.on(this, 'mousewheel', this.handleGlobalMousewheelEvent)
},
beforeDestroy () {
const panelElem = this.$refs.panel
if (panelElem && panelElem.parentNode) {
panelElem.parentNode.removeChild(panelElem)
}
},
destroyed () {
GlobalEvent.off(this, 'mousewheel')
},
render (h) {
const { $scopedSlots, $listeners, className, inited, type, destroyOnClose, isFormBtn, status, btnType, vSize, name, disabled, loading, showPanel, animatVisible, panelPlacement } = this
const downsSlot = $scopedSlots.dropdowns
return downsSlot ? h('div', {
class: ['vxe-button--dropdown', className, {
[`size--${vSize}`]: vSize,
'is--active': showPanel
}]
}, [
h('button', {
ref: 'xBtn',
class: ['vxe-button', `type--${btnType}`, {
[`size--${vSize}`]: vSize,
[`theme--${status}`]: status,
'is--round': this.round,
'is--circle': this.circle,
'is--disabled': disabled || loading,
'is--loading': loading
}],
attrs: {
name,
type: isFormBtn ? type : 'button',
disabled: disabled || loading
},
on: Object.assign({
mouseenter: this.mouseenterTargetEvent,
mouseleave: this.mouseleaveEvent
}, XEUtils.objectMap($listeners, (cb, type) => evnt => this.$emit(type, { $event: evnt })))
}, this.renderContent(h).concat([
h('i', {
class: `vxe-button--dropdown-arrow ${GlobalConfig.icon.BUTTON_DROPDOWN}`
})
])),
h('div', {
ref: 'panel',
class: ['vxe-button--dropdown-panel', {
[`size--${vSize}`]: vSize,
'animat--leave': animatVisible,
'animat--enter': showPanel
}],
attrs: {
placement: panelPlacement
},
style: this.panelStyle
}, inited ? [
h('div', {
class: 'vxe-button--dropdown-wrapper',
on: {
mousedown: this.mousedownDropdownEvent,
click: this.clickDropdownEvent,
mouseenter: this.mouseenterEvent,
mouseleave: this.mouseleaveEvent
}
}, destroyOnClose && !showPanel ? [] : downsSlot.call(this, {}, h))
] : null)
]) : h('button', {
ref: 'xBtn',
class: ['vxe-button', `type--${btnType}`, className, {
[`size--${vSize}`]: vSize,
[`theme--${status}`]: status,
'is--round': this.round,
'is--circle': this.circle,
'is--disabled': disabled || loading,
'is--loading': loading
}],
attrs: {
name,
type: isFormBtn ? type : 'button',
disabled: disabled || loading
},
on: XEUtils.objectMap($listeners, (cb, type) => evnt => this.$emit(type, { $event: evnt }))
}, this.renderContent(h))
},
methods: {
renderContent (h) {
const { $scopedSlots, content, icon, loading } = this
const contents = []
if (loading) {
contents.push(
h('i', {
class: ['vxe-button--loading-icon', GlobalConfig.icon.BUTTON_LOADING]
})
)
} else if ($scopedSlots.icon) {
contents.push(
h('span', {
class: 'vxe-button--custom-icon'
}, $scopedSlots.icon.call(this, {}))
)
} else if (icon) {
contents.push(
h('i', {
class: ['vxe-button--icon', icon]
})
)
}
if ($scopedSlots.default) {
contents.push(
h('span', {
class: 'vxe-button--content'
}, $scopedSlots.default.call(this, {}))
)
} else if (content) {
contents.push(
h('span', {
class: 'vxe-button--content'
}, [getFuncText(content)])
)
}
return contents
},
handleGlobalMousewheelEvent (evnt) {
if (this.showPanel && !DomTools.getEventTargetNode(evnt, this.$refs.panel).flag) {
this.closePanel()
}
},
updateZindex () {
if (this.panelIndex < UtilTools.getLastZIndex()) {
this.panelIndex = UtilTools.nextZIndex()
}
},
mousedownDropdownEvent (evnt) {
const isLeftBtn = evnt.button === 0
if (isLeftBtn) {
evnt.stopPropagation()
}
},
clickDropdownEvent (evnt) {
const dropdownElem = evnt.currentTarget
const panelElem = this.$refs.panel
const { flag, targetElem } = DomTools.getEventTargetNode(evnt, dropdownElem, 'vxe-button')
if (flag) {
if (panelElem) {
panelElem.dataset.active = 'N'
}
this.showPanel = false
setTimeout(() => {
if (!panelElem || panelElem.dataset.active !== 'Y') {
this.animatVisible = false
}
}, 350)
this.$emit('dropdown-click', { name: targetElem.getAttribute('name'), $event: evnt })
}
},
mouseenterTargetEvent () {
const panelElem = this.$refs.panel
panelElem.dataset.active = 'Y'
if (!this.inited) {
this.inited = true
if (this.transfer) {
document.body.appendChild(panelElem)
}
}
this.showTime = setTimeout(() => {
if (panelElem.dataset.active === 'Y') {
this.mouseenterEvent()
} else {
this.animatVisible = false
}
}, 250)
},
mouseenterEvent () {
const panelElem = this.$refs.panel
panelElem.dataset.active = 'Y'
this.animatVisible = true
setTimeout(() => {
if (panelElem.dataset.active === 'Y') {
this.showPanel = true
this.updateZindex()
this.updatePlacement()
setTimeout(() => {
if (this.showPanel) {
this.updatePlacement()
}
}, 50)
}
}, 20)
},
mouseleaveEvent () {
this.closePanel()
},
closePanel () {
const panelElem = this.$refs.panel
clearTimeout(this.showTime)
if (panelElem) {
panelElem.dataset.active = 'N'
setTimeout(() => {
if (panelElem.dataset.active !== 'Y') {
this.showPanel = false
setTimeout(() => {
if (panelElem.dataset.active !== 'Y') {
this.animatVisible = false
}
}, 350)
}
}, 100)
} else {
this.animatVisible = false
this.showPanel = false
}
},
updatePlacement () {
return this.$nextTick().then(() => {
const { $refs, transfer, placement, panelIndex } = this
const targetElem = $refs.xBtn
const panelElem = $refs.panel
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 { top, left, boundingTop, visibleHeight, visibleWidth } = DomTools.getAbsolutePos(targetElem)
let panelPlacement = 'bottom'
if (transfer) {
let btnLeft = left + targetWidth - panelWidth
let btnTop = top + targetHeight
if (placement === 'top') {
panelPlacement = 'top'
btnTop = top - panelHeight
} else if (!placement) {
// 如果下面不够放,则向上
if (boundingTop + targetHeight + panelHeight + marginSize > visibleHeight) {
panelPlacement = 'top'
btnTop = top - panelHeight
}
// 如果上面不够放,则向下(优先)
if (btnTop < marginSize) {
panelPlacement = 'bottom'
btnTop = top + targetHeight
}
}
// 如果溢出右边
if (btnLeft + panelWidth + marginSize > visibleWidth) {
btnLeft -= btnLeft + panelWidth + marginSize - visibleWidth
}
// 如果溢出左边
if (btnLeft < marginSize) {
btnLeft = marginSize
}
Object.assign(panelStyle, {
left: `${btnLeft}px`,
right: 'auto',
top: `${btnTop}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()
}
})
},
focus () {
this.$el.focus()
return this.$nextTick()
},
blur () {
this.$el.blur()
return this.$nextTick()
}
}
}