mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-11-30 02:08:12 +08:00
fix: Refactor dropdown (#454)
This commit is contained in:
parent
2932ba0e12
commit
8394a64478
@ -6,7 +6,7 @@ import css from 'rollup-plugin-css-only'
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
import typescript from 'rollup-plugin-typescript2'
|
||||
import pkg from '../package.json'
|
||||
|
||||
const deps = Object.keys(pkg.dependencies)
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const vue = require('./plugin.js')
|
||||
|
||||
@ -43,7 +43,7 @@ export default [
|
||||
],
|
||||
external(id) {
|
||||
return /^vue/.test(id)
|
||||
|| Object.keys(pkg.dependencies).some(k => new RegExp('^' + k).test(id))
|
||||
|| deps.some(k => new RegExp('^' + k).test(id))
|
||||
},
|
||||
},
|
||||
]
|
||||
|
@ -10,7 +10,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
|
||||
import path from 'path'
|
||||
import { getPackagesSync } from '@lerna/project'
|
||||
import pkg from '../package.json'
|
||||
|
||||
const deps = Object.keys(pkg.dependencies)
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const vue = require('./plugin.js')
|
||||
const inputs = getPackagesSync()
|
||||
@ -64,6 +64,6 @@ export default inputs.map(name => ({
|
||||
external(id) {
|
||||
return /^vue/.test(id)
|
||||
|| /^@element-plus/.test(id)
|
||||
|| Object.keys(pkg.dependencies).some(k => new RegExp('^' + k).test(id))
|
||||
|| deps.some(k => new RegExp('^' + k).test(id))
|
||||
},
|
||||
}))
|
||||
|
@ -50,9 +50,11 @@ describe('Dropdown', () => {
|
||||
)
|
||||
}
|
||||
})
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm.$refs.popper as any
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm as any
|
||||
const triggerElm = wrapper.find('.el-dropdown-link')
|
||||
expect(content.visible).toBe(false)
|
||||
await triggerElm.trigger('keydown')
|
||||
await triggerElm.trigger('focus')
|
||||
await triggerElm.trigger(MOUSE_ENTER_EVENT)
|
||||
await sleep(TIMEOUT)
|
||||
expect(content.visible).toBe(true)
|
||||
@ -91,7 +93,7 @@ describe('Dropdown', () => {
|
||||
},
|
||||
},
|
||||
)
|
||||
// const content = wrapper.findComponent({ ref: 'b' }).vm.$refs.popper as any
|
||||
// const content = wrapper.findComponent({ ref: 'b' }).vm as any
|
||||
const triggerElm = wrapper.find('.el-dropdown-link')
|
||||
await triggerElm.trigger(MOUSE_ENTER_EVENT)
|
||||
await sleep(TIMEOUT)
|
||||
@ -123,7 +125,7 @@ describe('Dropdown', () => {
|
||||
name: '',
|
||||
}),
|
||||
)
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm.$refs.popper as any
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm as any
|
||||
const triggerElm = wrapper.find('.el-dropdown-link')
|
||||
expect(content.visible).toBe(false)
|
||||
await triggerElm.trigger(MOUSE_ENTER_EVENT)
|
||||
@ -162,12 +164,14 @@ describe('Dropdown', () => {
|
||||
},
|
||||
},
|
||||
)
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm.$refs.popper as any
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm as any
|
||||
const triggerElm = wrapper.find('.el-dropdown__caret-button')
|
||||
const button = wrapper.find('.el-button')
|
||||
expect(content.visible).toBe(false)
|
||||
await button.trigger('click')
|
||||
expect((wrapper.vm as any).name).toBe('click')
|
||||
await triggerElm.trigger('keydown')
|
||||
await triggerElm.trigger('focus')
|
||||
await triggerElm.trigger(MOUSE_ENTER_EVENT)
|
||||
await sleep(TIMEOUT)
|
||||
expect(content.visible).toBe(true)
|
||||
@ -194,8 +198,10 @@ describe('Dropdown', () => {
|
||||
() => ({}),
|
||||
)
|
||||
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm.$refs.popper as any
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm as any
|
||||
const triggerElm = wrapper.find('.el-dropdown-link')
|
||||
await triggerElm.trigger('keydown')
|
||||
await triggerElm.trigger('focus')
|
||||
await triggerElm.trigger(MOUSE_ENTER_EVENT)
|
||||
await sleep(TIMEOUT)
|
||||
await wrapper.findComponent({ ref: 'c' }).trigger('click')
|
||||
@ -224,8 +230,10 @@ describe('Dropdown', () => {
|
||||
() => ({}),
|
||||
)
|
||||
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm.$refs.popper as any
|
||||
const content = wrapper.findComponent({ ref: 'b' }).vm as any
|
||||
const triggerElm = wrapper.find('.el-dropdown-link')
|
||||
await triggerElm.trigger('keydown')
|
||||
await triggerElm.trigger('focus')
|
||||
await triggerElm.trigger(MOUSE_ENTER_EVENT)
|
||||
await sleep(TIMEOUT)
|
||||
await triggerElm.trigger('keydown', {
|
||||
|
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<ul
|
||||
v-clickOutside:[triggerElm]="innerHide"
|
||||
:class="[size && `el-dropdown-menu--${size}`]"
|
||||
class="el-dropdown-menu"
|
||||
@mouseenter.stop="show"
|
||||
@ -10,10 +11,14 @@
|
||||
</template>
|
||||
<script lang='ts'>
|
||||
import { defineComponent, getCurrentInstance, onMounted } from 'vue'
|
||||
import { ClickOutside } from '@element-plus/directives'
|
||||
import { useDropdown, initDropdownDomEvent } from './useDropdown'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElDropdownMenu',
|
||||
directives: {
|
||||
ClickOutside,
|
||||
},
|
||||
setup() {
|
||||
const { _elDropdownSize, elDropdown } = useDropdown()
|
||||
const size = _elDropdownSize.value
|
||||
@ -38,6 +43,8 @@ export default defineComponent({
|
||||
size,
|
||||
show,
|
||||
hide,
|
||||
innerHide: _hide,
|
||||
triggerElm: elDropdown.triggerElm,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -1,20 +1,57 @@
|
||||
<template>
|
||||
<el-popper
|
||||
ref="triggerVnode"
|
||||
v-model:visible="visible"
|
||||
:placement="placement"
|
||||
:effect="effect"
|
||||
:manual-mode="true"
|
||||
:trigger="[trigger]"
|
||||
popper-class="el-dropdown-popper"
|
||||
>
|
||||
<template #default>
|
||||
<slot name="dropdown"></slot>
|
||||
</template>
|
||||
<template #trigger>
|
||||
<div class="el-dropdown">
|
||||
<slot v-if="!splitButton" name="default">
|
||||
</slot>
|
||||
<template v-else>
|
||||
<el-button-group>
|
||||
<el-button
|
||||
:size="dropdownSize"
|
||||
:type="type"
|
||||
@click="handlerMainButtonClick"
|
||||
>
|
||||
<slot name="default"></slot>
|
||||
</el-button>
|
||||
<el-button
|
||||
:size="dropdownSize"
|
||||
:type="type"
|
||||
class="el-dropdown__caret-button"
|
||||
>
|
||||
<i class="el-dropdown__icon el-icon-arrow-down"></i>
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-popper>
|
||||
</template>
|
||||
<script lang='ts'>
|
||||
import {
|
||||
defineComponent,
|
||||
h,
|
||||
provide,
|
||||
getCurrentInstance,
|
||||
ref,
|
||||
computed,
|
||||
watch,
|
||||
onMounted,
|
||||
VNode,
|
||||
nextTick,
|
||||
ComponentPublicInstance,
|
||||
watchEffect,
|
||||
} from 'vue'
|
||||
import { on, addClass, removeClass } from '@element-plus/utils/dom'
|
||||
import { Button as ElButton, ButtonGroup as ElButtonGroup } from '@element-plus/button'
|
||||
import { Popper as ELPopper } from '@element-plus/popper'
|
||||
import { Popper as ElPopper } from '@element-plus/popper'
|
||||
import { useDropdown } from './useDropdown'
|
||||
|
||||
export default defineComponent({
|
||||
@ -22,7 +59,7 @@ export default defineComponent({
|
||||
components: {
|
||||
ElButton,
|
||||
ElButtonGroup,
|
||||
ELPopper,
|
||||
ElPopper,
|
||||
},
|
||||
props: {
|
||||
trigger: {
|
||||
@ -61,7 +98,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
emits: ['visible-change', 'click', 'command'],
|
||||
setup(props, { emit, slots }) {
|
||||
setup(props, { emit }) {
|
||||
const _instance = getCurrentInstance()
|
||||
const { ELEMENT } = useDropdown()
|
||||
|
||||
@ -92,13 +129,13 @@ export default defineComponent({
|
||||
},
|
||||
)
|
||||
|
||||
const triggerVnode = ref<Nullable<VNode>>(null)
|
||||
const caretButton = ref<Nullable<ComponentPublicInstance>>(null)
|
||||
const triggerElm = computed<Nullable<HTMLButtonElement>>(() =>
|
||||
!props.splitButton
|
||||
? triggerVnode.value?.el
|
||||
: caretButton.value?.$el,
|
||||
)
|
||||
const triggerVnode = ref<Nullable<ComponentPublicInstance>>(null)
|
||||
const triggerElm = computed<Nullable<HTMLButtonElement>>(() =>{
|
||||
const _: any = (triggerVnode.value?.$refs.triggerRef as HTMLElement)?.children[0] ?? {}
|
||||
return !props.splitButton
|
||||
? _
|
||||
: _.children?.[1]
|
||||
})
|
||||
|
||||
function handleClick() {
|
||||
if (triggerElm.value?.disabled) return
|
||||
@ -145,13 +182,6 @@ export default defineComponent({
|
||||
triggerElm.value?.blur?.()
|
||||
}
|
||||
|
||||
// for dom
|
||||
Object.assign(_instance, {
|
||||
handleClick,
|
||||
hide,
|
||||
resetTabindex,
|
||||
})
|
||||
|
||||
const dropdownSize = computed(() => props.size || ELEMENT.size)
|
||||
function commandHandler (...args) {
|
||||
emit('command', ...args)
|
||||
@ -188,6 +218,12 @@ export default defineComponent({
|
||||
} else if (props.trigger === 'click') {
|
||||
on(triggerElm.value, 'click', handleClick)
|
||||
}
|
||||
|
||||
Object.assign(_instance, {
|
||||
handleClick,
|
||||
hide,
|
||||
resetTabindex,
|
||||
})
|
||||
})
|
||||
|
||||
const handlerMainButtonClick = event => {
|
||||
@ -195,49 +231,12 @@ export default defineComponent({
|
||||
hide()
|
||||
}
|
||||
|
||||
const onVisibleUpdate = (val: boolean) => visible.value = val
|
||||
|
||||
watchEffect(() => {
|
||||
triggerVnode.value = !props.splitButton
|
||||
? slots.default?.()[0]
|
||||
: h(ElButtonGroup, {}, {
|
||||
default: () => (
|
||||
[
|
||||
h(ElButton, {
|
||||
type: props.type,
|
||||
size: dropdownSize.value,
|
||||
onClick: handlerMainButtonClick,
|
||||
}, {
|
||||
default: () => slots.default?.()[0],
|
||||
}),
|
||||
h(ElButton, {
|
||||
type: props.type,
|
||||
size: dropdownSize.value,
|
||||
ref: caretButton,
|
||||
class: 'el-dropdown__caret-button',
|
||||
}, {
|
||||
default: () => h('i', { class: 'el-dropdown__icon el-icon-arrow-down' }),
|
||||
}),
|
||||
]
|
||||
),
|
||||
})
|
||||
})
|
||||
|
||||
return () => h(ELPopper, {
|
||||
ref: 'popper',
|
||||
placement: props.placement,
|
||||
effect: props.effect,
|
||||
visible: visible.value,
|
||||
manualMode: true,
|
||||
'onUpdate:visible': onVisibleUpdate,
|
||||
popperClass: 'el-dropdown-popper',
|
||||
trigger: [props.trigger],
|
||||
}, {
|
||||
default: () => slots.dropdown?.(),
|
||||
trigger: () => h('div', {
|
||||
class: 'el-dropdown',
|
||||
}, [triggerVnode.value]),
|
||||
})
|
||||
return {
|
||||
visible,
|
||||
dropdownSize,
|
||||
handlerMainButtonClick,
|
||||
triggerVnode,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
@ -85,7 +85,7 @@ export const initDropdownDomEvent = (dropdownChildren, triggerElm, _instance) =>
|
||||
triggerElm.setAttribute('aria-controls', listId.value)
|
||||
if (!_instance.props.splitButton) {
|
||||
triggerElm.setAttribute('role', 'button')
|
||||
triggerElm.setAttribute('tabindex', _instance.tabindex)
|
||||
triggerElm.setAttribute('tabindex', _instance.props.tabindex)
|
||||
addClass(triggerElm, 'el-dropdown-selfdefine')
|
||||
}
|
||||
}
|
||||
@ -104,7 +104,7 @@ export const initDropdownDomEvent = (dropdownChildren, triggerElm, _instance) =>
|
||||
}
|
||||
|
||||
function triggerElmFocus() {
|
||||
triggerElm?.focus?.()
|
||||
triggerElm.focus()
|
||||
}
|
||||
|
||||
initDomOperation()
|
||||
|
Loading…
Reference in New Issue
Block a user