feat(tree-select): support showPath (#805)

* feat: treeSelect support showPath

* chore: add CHANGELOG

* chore: add test case

* chore: update doc

* chore: update code

* chore: update type

* chore: upadte code

* chore: add dots

* chore: adjust code

Co-authored-by: 07akioni <07akioni2@gmail.com>
This commit is contained in:
zoomdong 2021-08-07 20:27:10 +08:00 committed by GitHub
parent 3f8e640f82
commit 60448314c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 105 additions and 8 deletions

View File

@ -4,7 +4,8 @@
### Feats
- `n-message-provider` add `closable` props, closes [#795](https://github.com/TuSimple/naive-ui/issues/795).
- `n-message-provider` add `closable` prop, closes [#795](https://github.com/TuSimple/naive-ui/issues/795).
- `n-tree-select` add `showPath` prop, closes[#625](https://github.com/TuSimple/naive-ui/issues/623).
- `n-layout` add `sider-placement` prop, closes [#566](https://github.com/TuSimple/naive-ui/issues/566).
### Fixes

View File

@ -5,6 +5,7 @@
### Feats
- `n-message-provider` 新增 `closable` 属性,关闭 [#795](https://github.com/TuSimple/naive-ui/issues/795)
- `n-tree-select` 新增 `showPath` 属性,关闭[#625](https://github.com/TuSimple/naive-ui/issues/623)
- `n-layout` 增加 `sider-placement` 属性,关闭 [#566](https://github.com/TuSimple/naive-ui/issues/566)
### Fixes

View File

@ -33,6 +33,8 @@ debug
| multiple | `boolean` | `false` | Whether to support multiple select. |
| options | `TreeSelectOption[]` | `[]` | Options. |
| placeholder | `string` | `'Please Select'` | Placeholder. |
| separator | `string` | `' / '` | Option value separator. |
| show-path | `boolean` | `false` | Whether to show path in selector. |
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | Component size. |
| value | `string \| number \| Array<string \| number> \| null>` | `undefined` | Selected key (or keys when multiple). |
| virtual-scroll | `boolean` | `true` | Whether to enable virtual scroll. |

View File

@ -7,6 +7,7 @@
<n-switch v-model:value="checkable" />Checkable
<n-switch v-model:value="cascade" />Cascade
<n-switch v-model:value="filterable" />Filterable
<n-switch v-model:value="showPath" />ShowPath
</n-space>
<n-tree-select
default-expand-all
@ -15,6 +16,7 @@
:checkable="checkable"
:cascade="cascade"
:filterable="filterable"
:showPath="showPath"
/>
</n-space>
```
@ -41,7 +43,8 @@ export default defineComponent({
checkable: ref(false),
cascade: ref(false),
filterable: ref(false),
options: createData()
options: createData(),
showPath: ref(false)
}
}
})

View File

@ -34,6 +34,8 @@ debug
| multiple | `boolean` | `false` | 是否支持多选 |
| options | `TreeSelectOption[]` | `[]` | 选项 |
| placeholder | `string` | `'请选择'` | 占位信息 |
| separator | `string` | `' / '` | 数据分隔符 |
| show-path | `boolean` | `false` | 是否在选择器中显示选项路径 |
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | 组件尺寸 |
| value | `string \| number \| Array<string \| number> \| null>` | `undefined` | 选中的 key |
| virtual-scroll | `boolean` | `true` | 是否开启虚拟滚动 |

View File

@ -48,7 +48,11 @@ import type {
Value
} from './interface'
import { treeSelectInjectionKey } from './interface'
import { treeOption2SelectOption, filterTree } from './utils'
import {
treeOption2SelectOption,
filterTree,
treeOption2SelectOptionWithPath
} from './utils'
import style from './styles/index.cssr'
const props = {
@ -79,6 +83,11 @@ const props = {
leafOnly: Boolean,
maxTagCount: [String, Number] as PropType<number | 'responsive'>,
multiple: Boolean,
showPath: Boolean,
separator: {
type: String,
default: ' / '
},
options: {
type: Array as PropType<TreeSelectOption[]>,
default: () => []
@ -231,23 +240,48 @@ export default defineComponent({
}
})
const selectedOptionRef = computed(() => {
if (props.multiple) return null
const { multiple, showPath, separator } = props
if (multiple) return null
const { value: mergedValue } = mergedValueRef
if (!Array.isArray(mergedValue) && mergedValue !== null) {
const tmNode = dataTreeMateRef.value.getNode(mergedValue)
if (tmNode !== null) return treeOption2SelectOption(tmNode.rawNode)
const { value: treeMate } = dataTreeMateRef
const tmNode = treeMate.getNode(mergedValue)
if (tmNode !== null) {
return showPath
? treeOption2SelectOptionWithPath(
tmNode.rawNode,
treeMate
.getPath(mergedValue)
.treeNodePath.map(({ rawNode }) => rawNode.label),
separator
)
: treeOption2SelectOption(tmNode.rawNode)
}
}
return null
})
const selectedOptionsRef = computed(() => {
if (!props.multiple) return null
const { multiple, showPath, separator } = props
if (!multiple) return null
const { value: mergedValue } = mergedValueRef
if (Array.isArray(mergedValue)) {
const res: SelectBaseOption[] = []
const { value: treeMate } = dataTreeMateRef
mergedValue.forEach((value) => {
const tmNode = treeMate.getNode(value)
if (tmNode !== null) res.push(treeOption2SelectOption(tmNode.rawNode))
if (tmNode !== null) {
res.push(
showPath
? treeOption2SelectOptionWithPath(
tmNode.rawNode,
treeMate
.getPath(value)
.treeNodePath.map(({ rawNode }) => rawNode.label),
separator
)
: treeOption2SelectOption(tmNode.rawNode)
)
}
})
return res
}

View File

@ -11,6 +11,18 @@ export function treeOption2SelectOption (
}
}
export function treeOption2SelectOptionWithPath (
treeOpt: TreeSelectOption,
treeNodePath: Key[],
separator: string
): SelectBaseOption {
return {
disabled: treeOpt.disabled,
value: treeOpt.key,
label: treeNodePath.join(separator)
}
}
export function filterTree (
tree: TreeSelectOption[],
filter: (pattern: string, v: TreeSelectOption) => boolean,

View File

@ -29,4 +29,46 @@ describe('n-tree-select', () => {
}
})
})
it('should show all path when set showPath', async () => {
const wrapper = mount(NTreeSelect, {
props: {
options: [
{
label: '1',
key: '1',
children: [
{
label: '1-1',
key: '1-1'
},
{
label: '1-2',
key: '1-2'
}
]
}
],
showPath: true,
defaultValue: '1-2'
}
})
expect(wrapper.find('.n-base-selection-label__input').exists()).toBe(true)
expect(wrapper.find('.n-base-selection-label__input').text()).toBe(
'1 / 1-2'
)
await wrapper.setProps({ showPath: false })
expect(wrapper.find('.n-base-selection-label__input').exists()).toBe(true)
expect(wrapper.find('.n-base-selection-label__input').text()).toBe('1-2')
await wrapper.setProps({
showPath: true,
defaultValue: '1-1',
separator: ' | '
})
expect(wrapper.find('.n-base-selection-label__input').exists()).toBe(true)
expect(wrapper.find('.n-base-selection-label__input').text()).toBe(
'1 | 1-2'
)
})
})