mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-11-30 18:27:40 +08:00
refactor(components): use css var to set menu global style (#3539)
* refactor(components): use css var to set menu global style * fix(components): remove useless value & change camelCase & test file * test: comment code that can not test final style * test: fix unused-vars lint * feat: add computed for useMenuCssVar * test(components): revert test file * fix(components): use computed value
This commit is contained in:
parent
2a0ebbc0b9
commit
35c90180d1
19
DEV_FAQ.md
Normal file
19
DEV_FAQ.md
Normal file
@ -0,0 +1,19 @@
|
||||
# DEV FAQ
|
||||
|
||||
Here are the problems that are easy to encounter in development.
|
||||
|
||||
## If you encounter dependency related issues
|
||||
|
||||
```bash
|
||||
yarn bootstrap
|
||||
```
|
||||
|
||||
## Test suite failed to run (jest)
|
||||
|
||||
Can not run `yarn test xxx`
|
||||
|
||||
```bash
|
||||
rm -rf dist
|
||||
```
|
||||
|
||||
Try again.
|
@ -37,27 +37,37 @@ describe('menu', () => {
|
||||
await nextTick()
|
||||
expect(item2.classes()).toContain('is-active')
|
||||
})
|
||||
|
||||
test('background-color', async () => {
|
||||
const backgroundColor = '#f00'
|
||||
const textColor = '#000'
|
||||
const activeTextColor = '#0f0'
|
||||
|
||||
const wrapper = _mount(
|
||||
`<el-menu default-active="2"
|
||||
background-color="#f00"
|
||||
text-color="#000"
|
||||
active-text-color="#0f0">
|
||||
background-color="${backgroundColor}"
|
||||
text-color="${textColor}"
|
||||
active-text-color="${activeTextColor}">
|
||||
<el-menu-item index="1" ref="item1">处理中心</el-menu-item>
|
||||
<el-menu-item index="2" ref="item2">订单管理</el-menu-item>
|
||||
</el-menu>`
|
||||
)
|
||||
const instance = wrapper.vm.$el
|
||||
const item1 = await wrapper.findComponent({ ref: 'item1' })
|
||||
const item2 = await wrapper.findComponent({ ref: 'item2' })
|
||||
// const item2 = await wrapper.findComponent({ ref: 'item2' })
|
||||
|
||||
expect(instance.style.backgroundColor).toEqual('rgb(255, 0, 0)')
|
||||
expect(item1.vm.$el.style.backgroundColor).toEqual('rgb(255, 0, 0)')
|
||||
expect(item1.vm.$el.style.color).toEqual('rgb(0, 0, 0)')
|
||||
expect(item2.vm.$el.style.color).toEqual('rgb(0, 255, 0)')
|
||||
expect(
|
||||
window.getComputedStyle(instance)._values['--el-menu-background-color']
|
||||
).toEqual(backgroundColor)
|
||||
|
||||
// We can not test final style, so comment it out for now.
|
||||
// expect(instance.style.backgroundColor).toEqual(backgroundColor)
|
||||
// expect(item1.vm.$el.style.backgroundColor).toEqual(backgroundColor)
|
||||
// expect(item1.vm.$el.style.color).toEqual(textColor)
|
||||
// expect(item2.vm.$el.style.color).toEqual(activeTextColor)
|
||||
await item1.trigger('mouseenter')
|
||||
await nextTick()
|
||||
expect(item1.vm.$el.style.backgroundColor).toEqual('rgb(204, 0, 0)')
|
||||
// expect(item1.vm.$el.style.backgroundColor).toEqual('rgb(204, 0, 0)')
|
||||
})
|
||||
test('menu-item click', async () => {
|
||||
const wrapper = _mount(
|
||||
@ -150,6 +160,7 @@ describe('menu', () => {
|
||||
const instance = elSubMenu.vm as any
|
||||
expect(instance.opened).toBeTruthy()
|
||||
})
|
||||
|
||||
test('hover-background-color', async () => {
|
||||
const wrapper = _mount(
|
||||
`<el-menu ref="menu" default-active="2"
|
||||
@ -169,10 +180,10 @@ describe('menu', () => {
|
||||
)
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.$refs.menu.hoverBackground).toEqual('rgb(0, 112, 93)')
|
||||
// expect(vm.$refs.menu.hoverBackground).toEqual('rgb(0, 112, 93)')
|
||||
vm.background = '#F00'
|
||||
await nextTick()
|
||||
expect(vm.$refs.menu.hoverBackground).toEqual('rgb(204, 0, 0)')
|
||||
// expect(vm.$refs.menu.hoverBackground).toEqual('rgb(204, 0, 0)')
|
||||
})
|
||||
|
||||
test('menu-overflow', async () => {
|
||||
|
@ -15,8 +15,7 @@ import { Resize } from '@element-plus/directives'
|
||||
import Menubar from '@element-plus/utils/menu/menu-bar'
|
||||
import ElMenuCollapseTransition from './menu-collapse-transition.vue'
|
||||
import ElSubMenu from './submenu.vue'
|
||||
import useMenuColor from './useMenuColor'
|
||||
|
||||
import { useMenuCssVar } from './use-menu-css-var'
|
||||
import type { VNode, Ref, ComputedRef } from 'vue'
|
||||
import type {
|
||||
IMenuProps,
|
||||
@ -70,8 +69,6 @@ export default defineComponent({
|
||||
const router = instance.appContext.config.globalProperties.$router
|
||||
const menu = ref(null)
|
||||
|
||||
const hoverBackground = useMenuColor(props)
|
||||
|
||||
// computed
|
||||
const isMenuPopup = computed(() => {
|
||||
return (
|
||||
@ -242,7 +239,6 @@ export default defineComponent({
|
||||
openedMenus,
|
||||
items,
|
||||
submenus,
|
||||
hoverBackground,
|
||||
activeIndex,
|
||||
isMenuPopup,
|
||||
|
||||
@ -274,7 +270,6 @@ export default defineComponent({
|
||||
expose({
|
||||
open,
|
||||
close,
|
||||
hoverBackground,
|
||||
})
|
||||
|
||||
const flattedChildren = (children) => {
|
||||
@ -350,6 +345,8 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
const ulStyle = useMenuCssVar(props)
|
||||
|
||||
const vnodeMenu = useVNodeResize(
|
||||
h(
|
||||
'ul',
|
||||
@ -357,7 +354,7 @@ export default defineComponent({
|
||||
key: String(props.collapse),
|
||||
role: 'menubar',
|
||||
ref: menu,
|
||||
style: { backgroundColor: props.backgroundColor || '' },
|
||||
style: ulStyle.value,
|
||||
class: {
|
||||
'el-menu': true,
|
||||
'el-menu--horizontal': props.mode === 'horizontal',
|
||||
|
@ -3,16 +3,12 @@
|
||||
class="el-menu-item"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
:style="[paddingStyle, itemStyle, { backgroundColor }]"
|
||||
:style="paddingStyle"
|
||||
:class="{
|
||||
'is-active': active,
|
||||
'is-disabled': disabled,
|
||||
}"
|
||||
@click="handleClick"
|
||||
@mouseenter="onMouseEnter"
|
||||
@focus="onMouseEnter"
|
||||
@blur="onMouseLeave"
|
||||
@mouseleave="onMouseLeave"
|
||||
>
|
||||
<el-tooltip
|
||||
v-if="
|
||||
@ -58,7 +54,7 @@ import {
|
||||
} from 'vue'
|
||||
import ElTooltip from '@element-plus/components/tooltip'
|
||||
import { Effect } from '@element-plus/components/popper'
|
||||
import useMenu from './useMenu'
|
||||
import useMenu from './use-menu'
|
||||
|
||||
import type { RootMenuProvider, SubMenuProvider } from './menu.type'
|
||||
|
||||
@ -92,48 +88,7 @@ export default defineComponent({
|
||||
const active = computed(() => {
|
||||
return props.index === rootMenu.activeIndex.value
|
||||
})
|
||||
const hoverBackground = computed(() => {
|
||||
return rootMenu.hoverBackground.value
|
||||
})
|
||||
const backgroundColor = computed(() => {
|
||||
return rootMenu.props.backgroundColor || ''
|
||||
})
|
||||
const activeTextColor = computed(() => {
|
||||
return rootMenu.props.activeTextColor || ''
|
||||
})
|
||||
const textColor = computed(() => {
|
||||
return rootMenu.props.textColor || ''
|
||||
})
|
||||
const mode = computed(() => {
|
||||
return rootMenu.props.mode
|
||||
})
|
||||
const isNested = computed(() => {
|
||||
return parentMenu.value.type.name !== 'ElMenu'
|
||||
})
|
||||
|
||||
const itemStyle = computed(() => {
|
||||
const style = {
|
||||
color: active.value ? activeTextColor.value : textColor.value,
|
||||
borderBottomColor: '',
|
||||
}
|
||||
if (mode.value === 'horizontal' && !isNested.value) {
|
||||
style.borderBottomColor = active.value
|
||||
? rootMenu.props.activeTextColor
|
||||
? activeTextColor.value
|
||||
: ''
|
||||
: 'transparent'
|
||||
}
|
||||
return style
|
||||
})
|
||||
|
||||
const onMouseEnter = () => {
|
||||
if (mode.value === 'horizontal' && !rootMenu.props.backgroundColor) return
|
||||
instance.vnode.el.style.backgroundColor = hoverBackground.value
|
||||
}
|
||||
const onMouseLeave = () => {
|
||||
if (mode.value === 'horizontal' && !rootMenu.props.backgroundColor) return
|
||||
instance.vnode.el.style.backgroundColor = backgroundColor.value
|
||||
}
|
||||
const handleClick = () => {
|
||||
if (!props.disabled) {
|
||||
rootMenu.methods.handleMenuItemClick({
|
||||
@ -165,12 +120,8 @@ export default defineComponent({
|
||||
slots,
|
||||
|
||||
paddingStyle,
|
||||
itemStyle,
|
||||
backgroundColor,
|
||||
active,
|
||||
handleClick,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -17,8 +17,9 @@ import {
|
||||
} from 'vue'
|
||||
import ElCollapseTransition from '@element-plus/components/collapse-transition'
|
||||
import ElPopper from '@element-plus/components/popper'
|
||||
import useMenu from './useMenu'
|
||||
import useMenu from './use-menu'
|
||||
|
||||
import { useMenuCssVar } from './use-menu-css-var'
|
||||
import type {
|
||||
ISubMenuProps,
|
||||
RootMenuProvider,
|
||||
@ -71,7 +72,6 @@ export default defineComponent({
|
||||
const {
|
||||
openedMenus,
|
||||
isMenuPopup,
|
||||
hoverBackground: rootHoverBackground,
|
||||
methods: rootMethods,
|
||||
props: rootProps,
|
||||
methods: { closeMenu },
|
||||
@ -265,16 +265,7 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
const handleTitleMouseenter = () => {
|
||||
if (mode.value === 'horizontal' && !rootProps.backgroundColor) return
|
||||
const title = popperVnode.value?.triggerRef || verticalTitleRef.value
|
||||
title && (title.style.backgroundColor = rootHoverBackground.value)
|
||||
}
|
||||
const handleTitleMouseleave = () => {
|
||||
if (mode.value === 'horizontal' && !rootProps.backgroundColor) return
|
||||
const title = popperVnode.value?.triggerRef || verticalTitleRef.value
|
||||
title && (title.style.backgroundColor = rootProps.backgroundColor || '')
|
||||
}
|
||||
|
||||
const updatePlacement = () => {
|
||||
data.currentPlacement =
|
||||
mode.value === 'horizontal' && isFirstLevel.value
|
||||
@ -342,8 +333,6 @@ export default defineComponent({
|
||||
handleClick,
|
||||
handleMouseenter,
|
||||
handleMouseleave,
|
||||
handleTitleMouseenter,
|
||||
handleTitleMouseleave,
|
||||
|
||||
addItem,
|
||||
removeItem,
|
||||
@ -365,9 +354,9 @@ export default defineComponent({
|
||||
null
|
||||
),
|
||||
]
|
||||
const ulStyle = {
|
||||
backgroundColor: this.rootProps.backgroundColor || '',
|
||||
}
|
||||
|
||||
const ulStyle = useMenuCssVar(this.rootProps)
|
||||
|
||||
// this render function is only used for bypass `Vue`'s compiler caused patching issue.
|
||||
// temporaryly mark ElPopper as any due to type inconsistency.
|
||||
// TODO: correct popper's type.
|
||||
@ -428,8 +417,6 @@ export default defineComponent({
|
||||
{ backgroundColor: this.backgroundColor },
|
||||
],
|
||||
onClick: this.handleClick,
|
||||
onMouseenter: this.handleTitleMouseenter,
|
||||
onMouseleave: this.handleTitleMouseleave,
|
||||
},
|
||||
titleTag
|
||||
),
|
||||
@ -447,8 +434,6 @@ export default defineComponent({
|
||||
],
|
||||
ref: 'verticalTitleRef',
|
||||
onClick: this.handleClick,
|
||||
onMouseenter: this.handleTitleMouseenter,
|
||||
onMouseleave: this.handleTitleMouseleave,
|
||||
},
|
||||
titleTag
|
||||
),
|
||||
@ -463,7 +448,7 @@ export default defineComponent({
|
||||
{
|
||||
role: 'menu',
|
||||
class: 'el-menu el-menu--inline',
|
||||
style: ulStyle,
|
||||
style: ulStyle.value,
|
||||
},
|
||||
[this.$slots.default?.()]
|
||||
),
|
||||
|
16
packages/components/menu/src/use-menu-css-var.ts
Normal file
16
packages/components/menu/src/use-menu-css-var.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { computed } from 'vue'
|
||||
import useMenuColor from './use-menu-color'
|
||||
|
||||
import type { IMenuProps } from './menu.type'
|
||||
|
||||
export const useMenuCssVar = (props: IMenuProps) => {
|
||||
return computed(() => {
|
||||
return {
|
||||
'--el-menu-text-color': props.textColor || '',
|
||||
'--el-menu-hover-text-color': props.textColor || '',
|
||||
'--el-menu-background-color': props.backgroundColor || '',
|
||||
'--el-menu-hover-background-color': useMenuColor(props).value || '',
|
||||
'--el-menu-active-color': props.activeTextColor || '',
|
||||
}
|
||||
})
|
||||
}
|
@ -896,10 +896,13 @@ $--slider: map.merge(
|
||||
$--menu: () !default;
|
||||
$--menu: map.merge(
|
||||
(
|
||||
'item-font-size': var(--el-font-size-base),
|
||||
'item-font-color': var(--el-text-color-primary),
|
||||
'item-hover-fill': var(--el-color-primary-light-9),
|
||||
'active-color': var(--el-color-primary),
|
||||
'text-color': var(--el-text-color-primary),
|
||||
'hover-text-color': var(--el-text-color-primary),
|
||||
'background-color': var(--el-color-white),
|
||||
'hover-background-color': var(--el-color-primary-light-9),
|
||||
'item-font-size': var(--el-font-size-base),
|
||||
'item-hover-fill': var(--el-color-primary-light-9),
|
||||
'border-color': #e6e6e6,
|
||||
),
|
||||
$--menu
|
||||
|
@ -8,7 +8,7 @@
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
font-size: var(--el-menu-item-font-size);
|
||||
color: var(--el-menu-item-font-color);
|
||||
color: var(--el-menu-text-color);
|
||||
padding: 0 20px;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
@ -24,7 +24,7 @@
|
||||
}
|
||||
|
||||
i {
|
||||
color: var(--el-text-color-secondary);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
@ -33,7 +33,7 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-menu-item-hover-fill);
|
||||
background-color: var(--el-menu-hover-background-color);
|
||||
}
|
||||
|
||||
@include when(disabled) {
|
||||
@ -68,7 +68,7 @@
|
||||
height: 60px;
|
||||
margin: 0;
|
||||
border-bottom: 2px solid transparent;
|
||||
color: var(--el-text-color-secondary);
|
||||
color: var(--el-menu-text-color);
|
||||
|
||||
a,
|
||||
a:hover {
|
||||
@ -88,14 +88,14 @@
|
||||
|
||||
&:hover {
|
||||
.#{$namespace}-sub-menu__title {
|
||||
color: var(--el-text-color-primary);
|
||||
color: var(--el-menu-hover-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
.#{$namespace}-sub-menu__title {
|
||||
border-bottom: 2px solid var(--el-color-primary);
|
||||
color: var(--el-text-color-primary);
|
||||
border-bottom: 2px solid var(--el-menu-active-color);
|
||||
color: var(--el-menu-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +103,7 @@
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
border-bottom: 2px solid transparent;
|
||||
color: var(--el-text-color-secondary);
|
||||
color: var(--el-menu-text-color);
|
||||
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
@ -120,27 +120,28 @@
|
||||
& .#{$namespace}-menu {
|
||||
& .#{$namespace}-menu-item,
|
||||
& .#{$namespace}-sub-menu__title {
|
||||
background-color: $--color-white;
|
||||
background-color: var(--el-menu-background-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
padding: 0 10px;
|
||||
color: var(--el-text-color-secondary);
|
||||
color: var(--el-menu-text-color);
|
||||
}
|
||||
|
||||
& .#{$namespace}-menu-item.is-active,
|
||||
& .#{$namespace}-sub-menu.is-active > .#{$namespace}-sub-menu__title {
|
||||
color: var(--el-text-color-primary);
|
||||
color: var(--el-menu-active-color);
|
||||
}
|
||||
}
|
||||
& .#{$namespace}-menu-item:not(.is-disabled):hover,
|
||||
& .#{$namespace}-menu-item:not(.is-disabled):focus {
|
||||
outline: none;
|
||||
color: var(--el-text-color-primary);
|
||||
color: var(--el-menu-hover-text-color);
|
||||
background-color: var(--el-menu-hover-background-color);
|
||||
}
|
||||
& > .#{$namespace}-menu-item.is-active {
|
||||
border-bottom: 2px solid var(--el-color-primary);
|
||||
color: var(--el-text-color-primary);
|
||||
border-bottom: 2px solid var(--el-menu-active-color);
|
||||
color: var(--el-menu-active-color) !important;
|
||||
}
|
||||
}
|
||||
@include m(collapse) {
|
||||
@ -197,7 +198,7 @@
|
||||
}
|
||||
|
||||
&.is-active i {
|
||||
color: var(--el-color-primary);
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,7 +223,7 @@
|
||||
vertical-align: middle;
|
||||
}
|
||||
@include when(active) {
|
||||
color: var(--el-color-primary);
|
||||
color: var(--el-menu-active-color);
|
||||
i {
|
||||
color: inherit;
|
||||
}
|
||||
@ -238,7 +239,7 @@
|
||||
@include menu-item;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--el-menu-item-hover-fill);
|
||||
background-color: var(--el-menu-hover-background-color);
|
||||
}
|
||||
}
|
||||
& .#{$namespace}-menu {
|
||||
@ -268,7 +269,7 @@
|
||||
}
|
||||
@include when(active) {
|
||||
.#{$namespace}-sub-menu__title {
|
||||
border-bottom-color: var(--el-color-primary);
|
||||
border-bottom-color: var(--el-menu-active-color);
|
||||
}
|
||||
}
|
||||
@include when(opened) {
|
||||
|
Loading…
Reference in New Issue
Block a user