diff --git a/packages/devui-vue/devui/tree-select/hooks/use-clear.ts b/packages/devui-vue/devui/tree-select/hooks/use-clear.ts index 0891d489f4..f81d37dfb8 100644 --- a/packages/devui-vue/devui/tree-select/hooks/use-clear.ts +++ b/packages/devui-vue/devui/tree-select/hooks/use-clear.ts @@ -5,22 +5,36 @@ import { TreeSelectProps } from '../src/tree-select-types' export default function useClear(props: TreeSelectProps, ctx: SetupContext, data: Ref): any { const isClearable = computed(() => { - return !props.disabled && props.allowClear && data.value.length > 0; + return !props.disabled && props.allowClear; }) - const handleClear = (e: MouseEvent) => { + const handleClearAll = (e: MouseEvent) => { e.preventDefault() e.stopPropagation() if (props.multiple) { ctx.emit('update:modelValue', []) + data.value = [] } else { ctx.emit('update:modelValue', '') data.value = '' } } + const handleClearItem = (e: MouseEvent, item?: string) => { + e.preventDefault() + e.stopPropagation() + if (props.multiple) { + data.value.splice(data.value.indexOf(item), 1) + ctx.emit('update:modelValue', data.value) + } else { + ctx.emit('update:modelValue', []) + data.value = [] + } + } + return { isClearable, - handleClear, + handleClearAll, + handleClearItem } } \ No newline at end of file diff --git a/packages/devui-vue/devui/tree-select/hooks/use-select.ts b/packages/devui-vue/devui/tree-select/hooks/use-select.ts index 24d0370065..5acdb01efa 100644 --- a/packages/devui-vue/devui/tree-select/hooks/use-select.ts +++ b/packages/devui-vue/devui/tree-select/hooks/use-select.ts @@ -2,7 +2,7 @@ import { ref } from 'vue' import { TreeSelectProps, TreeItem } from '../src/tree-select-types' export default function useSelect(props: TreeSelectProps): any { - const inputValue = ref('') + const inputValue = ref>([]) const selectedCache = new Set() const selectValue = (item: TreeItem) => { @@ -14,7 +14,7 @@ export default function useSelect(props: TreeSelectProps): any { useCache(item) searchUp(item) searchDown(item) - inputValue.value = [...selectedCache].toString() + inputValue.value = [...selectedCache] as string[] } } diff --git a/packages/devui-vue/devui/tree-select/src/tree-select-types.ts b/packages/devui-vue/devui/tree-select/src/tree-select-types.ts index 0809b4da2b..8aa6cf2ab6 100644 --- a/packages/devui-vue/devui/tree-select/src/tree-select-types.ts +++ b/packages/devui-vue/devui/tree-select/src/tree-select-types.ts @@ -52,6 +52,10 @@ export const treeSelectProps = { type: Boolean, default: false }, + enableLabelization: { + type: Boolean, + default: false + }, onToggleChange: { type: Function as PropType<(bool: boolean) => void>, default: undefined, diff --git a/packages/devui-vue/devui/tree-select/src/tree-select.scss b/packages/devui-vue/devui/tree-select/src/tree-select.scss index 85b3a7836f..6954cf41a3 100644 --- a/packages/devui-vue/devui/tree-select/src/tree-select.scss +++ b/packages/devui-vue/devui/tree-select/src/tree-select.scss @@ -41,13 +41,30 @@ $tree-select-item-font-size: 16px; cursor: pointer; width: 100%; height: $tree-select-input-height; - padding: 4px $tree-select-input-height 4px 10px; + padding: 0 10px; color: $devui-text; - vertical-align: middle; border: 1px solid $devui-form-control-line; border-radius: $devui-border-radius; outline: none; background-color: $devui-base-bg; + overflow: auto; + &:empty::before { + color:lightgrey; + content:attr(placeholder); + vertical-align: middle; + } +} + +.devui-tree-select-value { + display: inline-block; + height: 80%; + vertical-align: middle; +} + +.devui-tree-select-value-enableLabelization { + padding: 0 10px; + margin: 2px 10px 2px 0; + background-color: $devui-icon-fill; } .devui-tree-select-dropdown { @@ -105,6 +122,7 @@ $tree-select-item-font-size: 16px; .devui-tree-select-clear, .devui-tree-select-arrow { position: absolute; + top: 0; right: 0; height: 100%; width: $tree-select-input-height; diff --git a/packages/devui-vue/devui/tree-select/src/tree-select.tsx b/packages/devui-vue/devui/tree-select/src/tree-select.tsx index dfa35e0825..5c43c5b87f 100644 --- a/packages/devui-vue/devui/tree-select/src/tree-select.tsx +++ b/packages/devui-vue/devui/tree-select/src/tree-select.tsx @@ -1,41 +1,52 @@ import './tree-select.scss' -import { defineComponent, ref, Transition } from 'vue' +import { defineComponent, toRefs, Transition } from 'vue' import type { SetupContext } from 'vue' import { treeSelectProps, TreeSelectProps, TreeItem } from './tree-select-types' -import { attributeExtension, className } from './utils' +import { nodeMap, attributeExtension, className } from './utils' import useToggle from '../hooks/use-toggle' import useSelect from '../hooks/use-select' import useClear from '../hooks/use-clear' import IconOpen from '../assets/open.svg' import IconClose from '../assets/close.svg' import Checkbox from '../../checkbox/src/checkbox' +import ClickOutside from '../../shared/devui-directive/clickoutside' export default defineComponent({ name: 'DTreeSelect', + directives: { ClickOutside }, props: treeSelectProps, emits: ['toggleChange', 'valueChange', 'update:modelValue'], setup(props: TreeSelectProps, ctx: SetupContext) { - const { treeData, placeholder, disabled, multiple, leafOnly } = props + const { treeData, placeholder, disabled, multiple, leafOnly, enableLabelization } = toRefs(props) const { visible, selectToggle, treeToggle} = useToggle(props) const { inputValue, selectValue } = useSelect(props) - const { isClearable, handleClear} = useClear(props, ctx, inputValue) + const { isClearable, handleClearAll, handleClearItem} = useClear(props, ctx, inputValue) - const clickNode = (item: TreeItem)=> { - if(!leafOnly) { + const clickNode = (item: TreeItem) => { + if(!leafOnly.value) { selectValue(item) - !multiple && selectToggle(item) + !multiple.value && selectToggle(item) } else { if(!item.children) { selectValue(item) - !multiple && selectToggle(item) + !multiple.value && selectToggle(item) } } } + const deleteNode = (e: MouseEvent, item: string) => { + handleClearItem(e, item) + selectValue(nodeMap.get(item)) + } + const treeSelectCls = className('devui-tree-select', { 'devui-tree-select-open': visible.value, - 'devui-tree-select-disabled': disabled, + 'devui-tree-select-disabled': disabled.value, + }) + + const treeSelectInputItem = className('devui-tree-select-value', { + 'devui-tree-select-value-enableLabelization': enableLabelization.value }) const renderNode = (item) => ( @@ -50,7 +61,9 @@ export default defineComponent({ : treeToggle(e, item)} /> :{'\u00A0\u00A0\u00A0'} } - { multiple + {ctx.slots.default + ? ctx.slots.default({ item }) + : multiple.value ? item.halfchecked ? : @@ -74,19 +87,38 @@ export default defineComponent({ return () => { return ( -
+
visible.value = false}>
selectToggle()}> - - handleClear(e)} class="devui-tree-select-clear"> + /> */} +
+ { multiple.value + ? inputValue.value.map((item) => ( +
+ {item} + {enableLabelization.value + ? deleteNode(e, item)}/> + : ,} +
+ )) + : !Array.isArray(inputValue.value) &&
+ {inputValue.value} + {enableLabelization.value + && handleClearItem(e)}/>} +
+ } +
+ handleClearAll(e)} class="devui-tree-select-clear"> @@ -95,7 +127,7 @@ export default defineComponent({
-
    {renderTree(attributeExtension(treeData))}
+
    {renderTree(attributeExtension(treeData.value))}
diff --git a/packages/devui-vue/devui/tree-select/src/utils.ts b/packages/devui-vue/devui/tree-select/src/utils.ts index 30f3136a3c..ab4e3a4c2f 100644 --- a/packages/devui-vue/devui/tree-select/src/utils.ts +++ b/packages/devui-vue/devui/tree-select/src/utils.ts @@ -1,9 +1,12 @@ -import { TreeData } from '../src/tree-select-types' +import { TreeData, TreeItem } from '../src/tree-select-types' + +export const nodeMap = new Map() export function attributeExtension(data: TreeData): any { data.forEach((el) => { let level = 1 el.level = level + nodeMap.set(el.label, el) const nodeQueue = [] nodeQueue.push(el) while(nodeQueue.length !== 0) { @@ -12,6 +15,7 @@ export function attributeExtension(data: TreeData): any { node.children.forEach((el) => { el.level = level + 1 el.parent = node + nodeMap.set(el.label, el) nodeQueue.push(el) }) } diff --git a/packages/devui-vue/docs/components/tree-select/index.md b/packages/devui-vue/docs/components/tree-select/index.md index 97f4017f20..a8151a89ac 100644 --- a/packages/devui-vue/docs/components/tree-select/index.md +++ b/packages/devui-vue/docs/components/tree-select/index.md @@ -307,6 +307,257 @@ export default defineComponent({ ::: +### 自定义图标 + +:::demo + +```vue + + + +``` + +::: + +### 标签化 + +:::demo + +```vue + + +``` + +::: + +:::demo + +```vue + + +``` + +::: + + + + ### API d-select-tree 参数 @@ -319,6 +570,7 @@ d-select-tree 参数 | allowClear | boolean | false | 可选,值为 true 时可以清空输入框内容 | [可清空](#可清空) | | multiple | boolean | false | 可选,值为 true 时可选择多个项 | [多选](#多选) | | leafOnly | boolean | false | 可选,值为 true 时仅可选择叶子节点 | [仅叶子节点可选](#仅叶子节点可选) | +|enableLabelization| boolean | false | 可选,值为 true 时仅可选择叶子节点 | [标签化](#标签化) | ### 接口 & 类型定义