| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- import { PropType, CreateElement, VNode } from 'vue'
- import { defineVxeComponent } from '../../ui/src/comp'
- import XEUtils from 'xe-utils'
- import { getConfig, globalEvents, createEvent, globalMixins, ValueOf, renderEmptyElement } from '../../ui'
- import { getEventTargetNode, updatePanelPlacement } from '../../ui/src/dom'
- import { getLastZIndex, nextZIndex } from '../../ui/src/utils'
- import type { PulldownInternalData, VxePulldownPropTypes, VxePulldownEmits, VxeComponentSizeType, PulldownReactData, VxeFormConstructor, VxeFormPrivateMethods, VxeModalConstructor, VxeDrawerConstructor, VxeDrawerMethods, VxeModalMethods } from '../../../types'
- import type { VxeTableConstructor, VxeTablePrivateMethods } from '../../../types/components/table'
- export default /* define-vxe-component start */ defineVxeComponent({
- name: 'VxePulldown',
- model: {
- prop: 'value',
- event: 'modelValue'
- },
- mixins: [
- globalMixins.sizeMixin,
- globalMixins.permissionMixin
- ],
- props: {
- value: Boolean as PropType<VxePulldownPropTypes.ModelValue>,
- disabled: Boolean as PropType<VxePulldownPropTypes.Disabled>,
- placement: String as PropType<VxePulldownPropTypes.Placement>,
- trigger: {
- type: String as PropType<VxePulldownPropTypes.Trigger>,
- default: getConfig().pulldown.trigger
- },
- zIndex: Number as PropType<VxePulldownPropTypes.ZIndex>,
- size: {
- type: String as PropType<VxePulldownPropTypes.Size>,
- default: () => getConfig().pulldown.size || getConfig().size
- },
- options: Array as PropType<VxePulldownPropTypes.Options>,
- className: {
- type: [String, Function] as PropType<VxePulldownPropTypes.ClassName>,
- default: getConfig().pulldown.className
- },
- popupClassName: [String, Function] as PropType<VxePulldownPropTypes.PopupClassName>,
- showPopupShadow: Boolean as PropType<VxePulldownPropTypes.ShowPopupShadow>,
- destroyOnClose: {
- type: Boolean as PropType<VxePulldownPropTypes.DestroyOnClose>,
- default: getConfig().pulldown.destroyOnClose
- },
- transfer: {
- type: Boolean as PropType<VxePulldownPropTypes.Transfer>,
- default: null
- }
- },
- inject: {
- $xeModal: {
- default: null
- },
- $xeDrawer: {
- default: null
- },
- $xeTable: {
- default: null
- },
- $xeForm: {
- default: null
- }
- },
- data () {
- const xID = XEUtils.uniqueId()
- const reactData: PulldownReactData = {
- initialized: false,
- panelIndex: 0,
- panelStyle: {},
- panelPlacement: null,
- visiblePanel: false,
- isAniVisible: false,
- isActivated: false
- }
- const internalData: PulldownInternalData = {
- hpTimeout: undefined
- }
- return {
- xID,
- reactData,
- internalData
- }
- },
- computed: {
- ...({} as {
- computeSize(): VxeComponentSizeType
- $xeModal(): (VxeModalConstructor & VxeModalMethods) | null
- $xeDrawer(): (VxeDrawerConstructor & VxeDrawerMethods) | null
- $xeTable(): (VxeTableConstructor & VxeTablePrivateMethods) | null
- $xeForm(): (VxeFormConstructor & VxeFormPrivateMethods) | null
- }),
- computeBtnTransfer () {
- const $xePulldown = this
- const props = $xePulldown
- const $xeModal = $xePulldown.$xeModal
- const $xeDrawer = $xePulldown.$xeDrawer
- const $xeTable = $xePulldown.$xeTable
- const $xeForm = $xePulldown.$xeForm
- const { transfer } = props
- if (transfer === null) {
- const globalTransfer = getConfig().pulldown.transfer
- if (XEUtils.isBoolean(globalTransfer)) {
- return globalTransfer
- }
- if ($xeTable || $xeModal || $xeDrawer || $xeForm) {
- return true
- }
- }
- return transfer
- }
- },
- methods: {
- //
- // Method
- //
- dispatchEvent (type: ValueOf<VxePulldownEmits>, params: Record<string, any>, evnt: Event | null) {
- const $xePulldown = this
- $xePulldown.$emit(type, createEvent(evnt, { $pulldown: $xePulldown }, params))
- },
- emitModel (value: any) {
- const $xePulldown = this
- const { _events } = $xePulldown as any
- if (_events && _events.modelValue) {
- $xePulldown.$emit('modelValue', value)
- } else {
- $xePulldown.$emit('model-value', value)
- }
- },
- updateZindex () {
- const $xePulldown = this
- const props = $xePulldown
- const reactData = $xePulldown.reactData
- const { zIndex } = props
- if (zIndex) {
- reactData.panelIndex = zIndex
- } else if (reactData.panelIndex < getLastZIndex()) {
- reactData.panelIndex = nextZIndex()
- }
- },
- isPanelVisible () {
- const $xePulldown = this
- const reactData = $xePulldown.reactData
- return reactData.visiblePanel
- },
- /**
- * 手动更新位置
- */
- updatePlacement () {
- const $xePulldown = this
- const props = $xePulldown
- const reactData = $xePulldown.reactData
- const { placement } = props
- const { panelIndex } = reactData
- const targetElem = $xePulldown.$refs.refPulldownContent as HTMLElement
- const panelElem = $xePulldown.$refs.refPulldownPanel as HTMLDivElement
- const btnTransfer = $xePulldown.computeBtnTransfer
- const handleStyle = () => {
- const ppObj = updatePanelPlacement(targetElem, panelElem, {
- placement,
- teleportTo: btnTransfer
- })
- const panelStyle: { [key: string]: string | number } = Object.assign(ppObj.style, {
- zIndex: panelIndex
- })
- reactData.panelStyle = panelStyle
- reactData.panelPlacement = ppObj.placement
- }
- handleStyle()
- return $xePulldown.$nextTick().then(handleStyle)
- },
- /**
- * 显示下拉面板
- */
- showPanel () {
- const $xePulldown = this
- const props = $xePulldown
- const reactData = $xePulldown.reactData
- const internalData = $xePulldown.internalData
- const btnTransfer = $xePulldown.computeBtnTransfer
- const panelElem = $xePulldown.$refs.refPulldownPanel as HTMLElement
- if (!reactData.initialized) {
- reactData.initialized = true
- if (btnTransfer) {
- if (panelElem) {
- document.body.appendChild(panelElem)
- }
- }
- }
- return new Promise<void>(resolve => {
- if (!props.disabled) {
- if (internalData.hpTimeout) {
- clearTimeout(internalData.hpTimeout)
- }
- reactData.isActivated = true
- reactData.isAniVisible = true
- setTimeout(() => {
- reactData.visiblePanel = true
- $xePulldown.emitModel(true)
- $xePulldown.updatePlacement()
- setTimeout(() => {
- resolve($xePulldown.updatePlacement())
- }, 40)
- }, 10)
- $xePulldown.updateZindex()
- $xePulldown.dispatchEvent('visible-change', { visible: true }, null)
- } else {
- $xePulldown.$nextTick(() => {
- resolve()
- })
- }
- })
- },
- /**
- * 隐藏下拉面板
- */
- hidePanel () {
- const $xePulldown = this
- return $xePulldown.hideOptionPanel()
- },
- hideOptionPanel () {
- const $xePulldown = this
- const reactData = $xePulldown.reactData
- const internalData = $xePulldown.internalData
- reactData.visiblePanel = false
- $xePulldown.dispatchEvent('visible-change', { visible: false }, null)
- $xePulldown.emitModel(false)
- return new Promise<void>(resolve => {
- if (reactData.isAniVisible) {
- internalData.hpTimeout = setTimeout(() => {
- reactData.isAniVisible = false
- $xePulldown.$nextTick(() => {
- resolve()
- })
- }, 350)
- } else {
- $xePulldown.$nextTick(() => {
- resolve()
- })
- }
- })
- },
- /**
- * 切换下拉面板
- */
- togglePanel () {
- const $xePulldown = this
- const reactData = $xePulldown.reactData
- if (reactData.visiblePanel) {
- return $xePulldown.hideOptionPanel()
- }
- return $xePulldown.showPanel()
- },
- handleOptionEvent (evnt: Event, option: VxePulldownPropTypes.Option) {
- const $xePulldown = this
- const reactData = $xePulldown.reactData
- if (!option.disabled) {
- if (reactData.visiblePanel) {
- $xePulldown.hideOptionPanel()
- $xePulldown.dispatchEvent('hide-panel', {}, evnt)
- }
- $xePulldown.dispatchEvent('option-click', { option }, evnt)
- }
- },
- clickTargetEvent (evnt: MouseEvent) {
- const $xePulldown = this
- const props = $xePulldown
- const reactData = $xePulldown.reactData
- const { trigger } = props
- if (trigger === 'click') {
- if (reactData.visiblePanel) {
- $xePulldown.hideOptionPanel()
- $xePulldown.dispatchEvent('hide-panel', {}, evnt)
- } else {
- $xePulldown.showPanel()
- $xePulldown.dispatchEvent('show-panel', {}, evnt)
- }
- }
- $xePulldown.dispatchEvent('click', { $pulldown: $xePulldown }, evnt)
- },
- handleGlobalMousewheelEvent (evnt: Event) {
- const $xePulldown = this
- const props = $xePulldown
- const reactData = $xePulldown.reactData
- const { disabled } = props
- const { visiblePanel } = reactData
- const panelElem = $xePulldown.$refs.refPulldownPanel as HTMLElement
- if (!disabled) {
- if (visiblePanel) {
- if (getEventTargetNode(evnt, panelElem).flag) {
- $xePulldown.updatePlacement()
- } else {
- $xePulldown.hideOptionPanel()
- $xePulldown.dispatchEvent('hide-panel', {}, evnt)
- }
- }
- }
- },
- handleGlobalMousedownEvent (evnt: Event) {
- const $xePulldown = this
- const props = $xePulldown
- const reactData = $xePulldown.reactData
- const { disabled } = props
- const { visiblePanel } = reactData
- const el = $xePulldown.$refs.refElem as HTMLElement
- const panelElem = $xePulldown.$refs.refPulldownPanel as HTMLElement
- if (!disabled) {
- reactData.isActivated = getEventTargetNode(evnt, el).flag || getEventTargetNode(evnt, panelElem).flag
- if (visiblePanel && !reactData.isActivated) {
- $xePulldown.hideOptionPanel()
- $xePulldown.dispatchEvent('hide-panel', {}, evnt)
- }
- }
- },
- handleGlobalBlurEvent (evnt: Event) {
- const $xePulldown = this
- const reactData = $xePulldown.reactData
- const { visiblePanel, isActivated } = reactData
- if (visiblePanel) {
- $xePulldown.hideOptionPanel()
- $xePulldown.dispatchEvent('hide-panel', {}, evnt)
- }
- if (isActivated) {
- reactData.isActivated = false
- }
- },
- handleGlobalResizeEvent () {
- const $xePulldown = this
- const reactData = $xePulldown.reactData
- const { visiblePanel } = reactData
- if (visiblePanel) {
- $xePulldown.updatePlacement()
- }
- },
- //
- // Render
- //
- renderDefaultPanel (h: CreateElement, options?: VxePulldownPropTypes.Options) {
- const $xePulldown = this
- const slots = $xePulldown.$scopedSlots
- const optionSlot = slots.option
- return h('div', {
- class: 'vxe-pulldown--panel-list'
- }, options
- ? options.map(item => {
- return h('div', {
- class: 'vxe-pulldown--panel-item',
- on: {
- click (evnt: Event) {
- $xePulldown.handleOptionEvent(evnt, item)
- }
- }
- }, optionSlot ? optionSlot({ $pulldown: $xePulldown, option: item }) : `${item.label || ''}`)
- })
- : []
- )
- },
- renderVN (h: CreateElement): VNode {
- const $xePulldown = this
- const props = $xePulldown
- const slots = $xePulldown.$scopedSlots
- const reactData = $xePulldown.reactData
- const { className, options, popupClassName, showPopupShadow, destroyOnClose, disabled } = props
- const { initialized, isActivated, isAniVisible, visiblePanel, panelStyle, panelPlacement } = reactData
- const btnTransfer = $xePulldown.computeBtnTransfer
- const vSize = $xePulldown.computeSize
- const defaultSlot = slots.default
- const headerSlot = slots.header
- const footerSlot = slots.footer
- const dropdownSlot = slots.dropdown
- return h('div', {
- ref: 'refElem',
- class: ['vxe-pulldown', className ? (XEUtils.isFunction(className) ? className({ $pulldown: $xePulldown }) : className) : '', {
- [`size--${vSize}`]: vSize,
- 'is--visible': visiblePanel,
- 'is--disabled': disabled,
- 'is--active': isActivated
- }]
- }, [
- h('div', {
- ref: 'refPulldownContent',
- class: 'vxe-pulldown--content',
- on: {
- click: $xePulldown.clickTargetEvent
- }
- }, defaultSlot ? defaultSlot({ $pulldown: $xePulldown }) : []),
- h('div', {
- ref: 'refPulldownPanel',
- class: ['vxe-table--ignore-clear vxe-pulldown--panel', popupClassName ? (XEUtils.isFunction(popupClassName) ? popupClassName({ $pulldown: $xePulldown }) : popupClassName) : '', {
- [`size--${vSize}`]: vSize,
- 'is--transfer': btnTransfer,
- 'ani--leave': isAniVisible,
- 'ani--enter': visiblePanel
- }],
- attrs: {
- placement: panelPlacement
- },
- style: panelStyle
- }, initialized
- ? [
- h('div', {
- class: ['vxe-pulldown--panel-wrapper', {
- 'is--shadow': showPopupShadow
- }]
- }, initialized && (destroyOnClose ? (visiblePanel || isAniVisible) : true)
- ? [
- headerSlot
- ? h('div', {
- class: 'vxe-pulldown--panel-header'
- }, headerSlot({ $pulldown: $xePulldown }))
- : renderEmptyElement($xePulldown),
- h('div', {
- class: 'vxe-pulldown--panel-body'
- }, dropdownSlot
- ? dropdownSlot({ $pulldown: $xePulldown })
- : [
- $xePulldown.renderDefaultPanel(h, options)
- ]),
- footerSlot
- ? h('div', {
- class: 'vxe-pulldown--panel-footer'
- }, footerSlot({ $pulldown: $xePulldown }))
- : renderEmptyElement($xePulldown)
- ]
- : [])
- ]
- : [])
- ])
- }
- },
- watch: {
- value (val) {
- const $xePulldown = this
- const reactData = $xePulldown.reactData
- reactData.isActivated = !!val
- if (val) {
- $xePulldown.showPanel()
- } else {
- $xePulldown.hideOptionPanel()
- }
- }
- },
- created () {
- const $xePulldown = this
- const props = $xePulldown
- if (props.value) {
- $xePulldown.showPanel()
- }
- globalEvents.on($xePulldown, 'mousewheel', $xePulldown.handleGlobalMousewheelEvent)
- globalEvents.on($xePulldown, 'mousedown', $xePulldown.handleGlobalMousedownEvent)
- globalEvents.on($xePulldown, 'blur', $xePulldown.handleGlobalBlurEvent)
- globalEvents.on($xePulldown, 'resize', $xePulldown.handleGlobalResizeEvent)
- },
- beforeDestroy () {
- const $xePulldown = this
- const panelElem = $xePulldown.$refs.refPulldownPanel as HTMLElement | undefined
- if (panelElem && panelElem.parentNode) {
- panelElem.parentNode.removeChild(panelElem)
- }
- globalEvents.off($xePulldown, 'mousewheel')
- globalEvents.off($xePulldown, 'mousedown')
- globalEvents.off($xePulldown, 'blur')
- globalEvents.off($xePulldown, 'resize')
- },
- render (this: any, h) {
- return this.renderVN(h)
- }
- }) /* define-vxe-component end */
|