mirror of
https://github.com/element-plus/element-plus.git
synced 2024-11-21 01:02:59 +08:00
refactor(components): [cascader,cascader-panel] add namespace (#5589)
Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
This commit is contained in:
parent
d3915ed493
commit
5a9d5ea5fb
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
:class="['el-cascader-panel', border && 'is-bordered']"
|
||||
:class="[ns.b('panel'), ns.is('bordered', border)]"
|
||||
@keydown="handleKeyDown"
|
||||
>
|
||||
<el-cascader-menu
|
||||
@ -40,6 +40,7 @@ import {
|
||||
UPDATE_MODEL_EVENT,
|
||||
CHANGE_EVENT,
|
||||
} from '@element-plus/constants'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
|
||||
import ElCascaderMenu from './menu.vue'
|
||||
import Store from './store'
|
||||
@ -82,6 +83,7 @@ export default defineComponent({
|
||||
// for interrupt sync check status in lazy mode
|
||||
let manualChecked = false
|
||||
|
||||
const ns = useNamespace('cascader')
|
||||
const config = useCascaderConfig(props)
|
||||
|
||||
let store: Nullable<Store> = null
|
||||
@ -273,13 +275,13 @@ export default defineComponent({
|
||||
menuList.value.forEach((menu) => {
|
||||
const menuElement = menu?.$el
|
||||
if (menuElement) {
|
||||
const container = (menuElement as HTMLElement).querySelector(
|
||||
'.el-scrollbar__wrap'
|
||||
const container = menuElement.querySelector(
|
||||
`.${ns.namespace.value}scrollbar__wrap`
|
||||
)
|
||||
const activeNode =
|
||||
menuElement.querySelector('.el-cascader-node.is-active') ||
|
||||
menuElement.querySelector('.el-cascader-node.in-active-path')
|
||||
scrollIntoView(container as HTMLElement, activeNode)
|
||||
menuElement.querySelector(`.${ns.b('node')}.${ns.is('active')}`) ||
|
||||
menuElement.querySelector(`.${ns.b('node')}.in-active-path`)
|
||||
scrollIntoView(container, activeNode)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -294,7 +296,7 @@ export default defineComponent({
|
||||
e.preventDefault()
|
||||
const distance = code === EVENT_CODE.up ? -1 : 1
|
||||
focusNode(
|
||||
getSibling(target, distance, '.el-cascader-node[tabindex="-1"]')
|
||||
getSibling(target, distance, `.${ns.b('node')}[tabindex="-1"]`)
|
||||
)
|
||||
break
|
||||
}
|
||||
@ -302,7 +304,7 @@ export default defineComponent({
|
||||
e.preventDefault()
|
||||
const preMenu = menuList.value[getMenuIndex(target) - 1]
|
||||
const expandedNode = preMenu?.$el.querySelector(
|
||||
'.el-cascader-node[aria-expanded="true"]'
|
||||
`.${ns.b('node')}[aria-expanded="true"]`
|
||||
)
|
||||
focusNode(expandedNode)
|
||||
break
|
||||
@ -311,7 +313,7 @@ export default defineComponent({
|
||||
e.preventDefault()
|
||||
const nextMenu = menuList.value[getMenuIndex(target) + 1]
|
||||
const firstNode = nextMenu?.$el.querySelector(
|
||||
'.el-cascader-node[tabindex="-1"]'
|
||||
`.${ns.b('node')}[tabindex="-1"]`
|
||||
)
|
||||
focusNode(firstNode)
|
||||
break
|
||||
@ -366,6 +368,7 @@ export default defineComponent({
|
||||
onMounted(() => !isEmpty(props.modelValue) && syncCheckedValue())
|
||||
|
||||
return {
|
||||
ns,
|
||||
menuList,
|
||||
menus,
|
||||
checkedNodes,
|
||||
|
@ -3,9 +3,9 @@
|
||||
:key="menuId"
|
||||
tag="ul"
|
||||
role="menu"
|
||||
class="el-cascader-menu"
|
||||
wrap-class="el-cascader-menu__wrap"
|
||||
:view-class="['el-cascader-menu__list', isEmpty && 'is-empty']"
|
||||
:class="ns.b()"
|
||||
:wrap-class="ns.e('wrap')"
|
||||
:view-class="[ns.e('list'), ns.is('empty', isEmpty)]"
|
||||
@mousemove="handleMouseMove"
|
||||
@mouseleave="clearHoverZone"
|
||||
>
|
||||
@ -16,19 +16,19 @@
|
||||
:menu-id="menuId"
|
||||
@expand="handleExpand"
|
||||
/>
|
||||
<div v-if="isLoading" class="el-cascader-menu__empty-text">
|
||||
<el-icon size="14" class="is-loading">
|
||||
<div v-if="isLoading" :class="ns.e('empty-text')">
|
||||
<el-icon size="14" :class="ns.is('loading')">
|
||||
<loading />
|
||||
</el-icon>
|
||||
{{ t('el.cascader.loading') }}
|
||||
</div>
|
||||
<div v-else-if="isEmpty" class="el-cascader-menu__empty-text">
|
||||
<div v-else-if="isEmpty" :class="ns.e('empty-text')">
|
||||
{{ t('el.cascader.noData') }}
|
||||
</div>
|
||||
<svg
|
||||
v-else-if="panel?.isHoverMenu"
|
||||
ref="hoverZone"
|
||||
class="el-cascader-menu__hover-zone"
|
||||
:class="ns.e('hover-zone')"
|
||||
></svg>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
@ -36,7 +36,7 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, getCurrentInstance, inject, ref } from 'vue'
|
||||
import ElScrollbar from '@element-plus/components/scrollbar'
|
||||
import { useLocale } from '@element-plus/hooks'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import { generateId } from '@element-plus/utils'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import ElIcon from '@element-plus/components/icon'
|
||||
@ -70,6 +70,8 @@ export default defineComponent({
|
||||
|
||||
setup(props) {
|
||||
const instance = getCurrentInstance()!
|
||||
const ns = useNamespace('cascader-menu')
|
||||
|
||||
const { t } = useLocale()
|
||||
const id = generateId()
|
||||
let activeNode: Nullable<HTMLElement> = null
|
||||
@ -124,6 +126,7 @@ export default defineComponent({
|
||||
clearHoverTimer()
|
||||
}
|
||||
return {
|
||||
ns,
|
||||
panel,
|
||||
hoverZone,
|
||||
isEmpty,
|
||||
|
@ -1,14 +1,21 @@
|
||||
import { defineComponent, h } from 'vue'
|
||||
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
export default defineComponent({
|
||||
name: 'NodeContent',
|
||||
setup() {
|
||||
const ns = useNamespace('cascader-node')
|
||||
return {
|
||||
ns,
|
||||
}
|
||||
},
|
||||
render() {
|
||||
const { ns } = this
|
||||
const { node, panel } = this.$parent
|
||||
const { data, label } = node
|
||||
const { renderLabelFn } = panel
|
||||
return h(
|
||||
'span',
|
||||
{ class: 'el-cascader-node__label' },
|
||||
{ class: ns.e('label') },
|
||||
renderLabelFn ? renderLabelFn({ node, data }) : label
|
||||
)
|
||||
},
|
||||
|
@ -7,12 +7,12 @@
|
||||
:aria-expanded="inExpandingPath"
|
||||
:tabindex="expandable ? -1 : undefined"
|
||||
:class="[
|
||||
'el-cascader-node',
|
||||
checkStrictly && 'is-selectable',
|
||||
ns.b(),
|
||||
ns.is('selectable', checkStrictly),
|
||||
ns.is('active', node.checked),
|
||||
ns.is('disabled', !expandable),
|
||||
inExpandingPath && 'in-active-path',
|
||||
inCheckedPath && 'in-checked-path',
|
||||
node.checked && 'is-active',
|
||||
!expandable && 'is-disabled',
|
||||
]"
|
||||
@mouseenter="handleHoverExpand"
|
||||
@focus="handleHoverExpand"
|
||||
@ -41,10 +41,7 @@
|
||||
-->
|
||||
<span></span>
|
||||
</el-radio>
|
||||
<el-icon
|
||||
v-else-if="isLeaf && node.checked"
|
||||
class="el-cascader-node__prefix"
|
||||
>
|
||||
<el-icon v-else-if="isLeaf && node.checked" :class="ns.e('prefix')">
|
||||
<check />
|
||||
</el-icon>
|
||||
|
||||
@ -53,10 +50,10 @@
|
||||
|
||||
<!-- postfix -->
|
||||
<template v-if="!isLeaf">
|
||||
<el-icon v-if="node.loading" class="is-loading el-cascader-node__postfix">
|
||||
<el-icon v-if="node.loading" :class="[ns.is('loading'), ns.e('postfix')]">
|
||||
<loading />
|
||||
</el-icon>
|
||||
<el-icon v-else class="arrow-right el-cascader-node__postfix">
|
||||
<el-icon v-else :class="['arrow-right', ns.e('postfix')]">
|
||||
<arrow-right />
|
||||
</el-icon>
|
||||
</template>
|
||||
@ -68,6 +65,7 @@ import { computed, defineComponent, inject } from 'vue'
|
||||
import ElCheckbox from '@element-plus/components/checkbox'
|
||||
import ElRadio from '@element-plus/components/radio'
|
||||
import ElIcon from '@element-plus/components/icon'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { Check, Loading, ArrowRight } from '@element-plus/icons-vue'
|
||||
import NodeContent from './node-content'
|
||||
import { CASCADER_PANEL_INJECTION_KEY } from './types'
|
||||
@ -101,6 +99,7 @@ export default defineComponent({
|
||||
setup(props, { emit }) {
|
||||
const panel = inject(CASCADER_PANEL_INJECTION_KEY)!
|
||||
|
||||
const ns = useNamespace('cascader-node')
|
||||
const isHoverMenu = computed(() => panel.isHoverMenu)
|
||||
const multiple = computed(() => panel.config.multiple)
|
||||
const checkStrictly = computed(() => panel.config.checkStrictly)
|
||||
@ -197,6 +196,7 @@ export default defineComponent({
|
||||
expandable,
|
||||
inExpandingPath,
|
||||
inCheckedPath,
|
||||
ns,
|
||||
handleHoverExpand,
|
||||
handleExpand,
|
||||
handleClick,
|
||||
|
@ -3,7 +3,7 @@
|
||||
ref="tooltipRef"
|
||||
v-model:visible="popperVisible"
|
||||
:teleported="compatTeleported"
|
||||
:popper-class="`el-cascader__dropdown ${popperClass}`"
|
||||
:popper-class="[nsCascader.e('dropdown'), popperClass]"
|
||||
:popper-options="popperOptions"
|
||||
:fallback-placements="[
|
||||
'bottom-start',
|
||||
@ -16,7 +16,7 @@
|
||||
:stop-popper-mouse-event="false"
|
||||
:gpu-acceleration="false"
|
||||
placement="bottom-start"
|
||||
transition="el-zoom-in-top"
|
||||
:transition="`${nsCascader.namespace.value}-zoom-in-top`"
|
||||
effect="light"
|
||||
pure
|
||||
persistent
|
||||
@ -26,9 +26,9 @@
|
||||
<div
|
||||
v-clickoutside:[popperPaneRef]="() => togglePopperVisible(false)"
|
||||
:class="[
|
||||
'el-cascader',
|
||||
realSize && `el-cascader--${realSize}`,
|
||||
{ 'is-disabled': isDisabled },
|
||||
nsCascader.b(),
|
||||
nsCascader.m(realSize),
|
||||
nsCascader.is('disabled', isDisabled),
|
||||
$attrs.class,
|
||||
]"
|
||||
:style="$attrs.style"
|
||||
@ -45,7 +45,7 @@
|
||||
:disabled="isDisabled"
|
||||
:validate-event="false"
|
||||
:size="realSize"
|
||||
:class="{ 'is-focus': popperVisible }"
|
||||
:class="nsCascader.is('focus', popperVisible)"
|
||||
@compositionstart="handleComposition"
|
||||
@compositionupdate="handleComposition"
|
||||
@compositionend="handleComposition"
|
||||
@ -57,7 +57,7 @@
|
||||
<el-icon
|
||||
v-if="clearBtnVisible"
|
||||
key="clear"
|
||||
class="el-input__icon icon-circle-close"
|
||||
:class="[nsInput.e('icon'), 'icon-circle-close']"
|
||||
@click.stop="handleClear"
|
||||
>
|
||||
<circle-close />
|
||||
@ -66,9 +66,9 @@
|
||||
v-else
|
||||
key="arrow-down"
|
||||
:class="[
|
||||
'el-input__icon',
|
||||
nsInput.e('icon'),
|
||||
'icon-arrow-down',
|
||||
popperVisible && 'is-reverse',
|
||||
nsCascader.is('reverse', popperVisible),
|
||||
]"
|
||||
@click.stop="togglePopperVisible()"
|
||||
>
|
||||
@ -77,7 +77,7 @@
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<div v-if="multiple" ref="tagWrapper" class="el-cascader__tags">
|
||||
<div v-if="multiple" ref="tagWrapper" :class="nsCascader.e('tags')">
|
||||
<el-tag
|
||||
v-for="tag in presentTags"
|
||||
:key="tag.key"
|
||||
@ -94,7 +94,7 @@
|
||||
v-if="filterable && !isDisabled"
|
||||
v-model="searchInputValue"
|
||||
type="text"
|
||||
class="el-cascader__search-input"
|
||||
:class="nsCascader.e('search-input')"
|
||||
:placeholder="presentText ? '' : inputPlaceholder"
|
||||
@input="(e) => handleInput(searchInputValue, e)"
|
||||
@click.stop="togglePopperVisible(true)"
|
||||
@ -124,8 +124,8 @@
|
||||
v-show="filtering"
|
||||
ref="suggestionPanel"
|
||||
tag="ul"
|
||||
class="el-cascader__suggestion-panel"
|
||||
view-class="el-cascader__suggestion-list"
|
||||
:class="nsCascader.e('suggestion-panel')"
|
||||
:view-class="nsCascader.e('suggestion-list')"
|
||||
@keydown="handleSuggestionKeyDown"
|
||||
>
|
||||
<template v-if="suggestions.length">
|
||||
@ -133,8 +133,8 @@
|
||||
v-for="item in suggestions"
|
||||
:key="item.uid"
|
||||
:class="[
|
||||
'el-cascader__suggestion-item',
|
||||
item.checked && 'is-checked',
|
||||
nsCascader.e('suggestion-item'),
|
||||
nsCascader.is('checked', item.checked),
|
||||
]"
|
||||
:tabindex="-1"
|
||||
@click="handleSuggestionClick(item)"
|
||||
@ -144,7 +144,7 @@
|
||||
</li>
|
||||
</template>
|
||||
<slot v-else name="empty">
|
||||
<li class="el-cascader__empty-text">
|
||||
<li :class="nsCascader.e('empty-text')">
|
||||
{{ t('el.cascader.noMatch') }}
|
||||
</li>
|
||||
</slot>
|
||||
@ -182,7 +182,7 @@ import ElIcon from '@element-plus/components/icon'
|
||||
|
||||
import { formContextKey, formItemContextKey } from '@element-plus/tokens'
|
||||
import { ClickOutside as Clickoutside } from '@element-plus/directives'
|
||||
import { useLocale, useSize } from '@element-plus/hooks'
|
||||
import { useLocale, useSize, useNamespace } from '@element-plus/hooks'
|
||||
|
||||
import {
|
||||
focusNode,
|
||||
@ -323,6 +323,9 @@ export default defineComponent({
|
||||
COMPONENT_NAME,
|
||||
'popperAppendToBody'
|
||||
)
|
||||
const nsCascader = useNamespace('cascader')
|
||||
const nsInput = useNamespace('input')
|
||||
|
||||
const { t } = useLocale()
|
||||
const elForm = inject(formContextKey, {} as FormContext)
|
||||
const elFormItem = inject(formItemContextKey, {} as FormItemContext)
|
||||
@ -497,11 +500,11 @@ export default defineComponent({
|
||||
|
||||
if (filtering.value && suggestionPanel.value) {
|
||||
firstNode = suggestionPanel.value.$el.querySelector(
|
||||
'.el-cascader__suggestion-item'
|
||||
`.${nsCascader.e('suggestion-item')}`
|
||||
)
|
||||
} else {
|
||||
firstNode = panel.value?.$el.querySelector(
|
||||
'.el-cascader-node[tabindex="-1"]'
|
||||
`.${nsCascader.b('node')}[tabindex="-1"]`
|
||||
)
|
||||
}
|
||||
|
||||
@ -520,7 +523,7 @@ export default defineComponent({
|
||||
|
||||
if (suggestionPanelEl) {
|
||||
const suggestionList = suggestionPanelEl.querySelector(
|
||||
'.el-cascader__suggestion-list'
|
||||
`.${nsCascader.e('suggestion-list')}`
|
||||
)
|
||||
suggestionList.style.minWidth = `${inputInner.offsetWidth}px`
|
||||
}
|
||||
@ -603,7 +606,7 @@ export default defineComponent({
|
||||
getSibling(
|
||||
target,
|
||||
distance,
|
||||
'.el-cascader__suggestion-item[tabindex="-1"]'
|
||||
`.${nsCascader.e('suggestion-item')}[tabindex="-1"]`
|
||||
)
|
||||
)
|
||||
break
|
||||
@ -709,6 +712,8 @@ export default defineComponent({
|
||||
// deprecation in ver 2.1.0
|
||||
compatTeleported,
|
||||
|
||||
nsCascader,
|
||||
nsInput,
|
||||
t,
|
||||
togglePopperVisible,
|
||||
hideSuggestionPanel,
|
||||
|
Loading…
Reference in New Issue
Block a user