refactor(components): [cascader,cascader-panel] add namespace (#5589)

Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
This commit is contained in:
gjfei 2022-03-07 22:30:45 +08:00 committed by GitHub
parent d3915ed493
commit 5a9d5ea5fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 50 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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
)
},

View File

@ -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,

View File

@ -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,