mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-03-01 13:36:55 +08:00
feat(tabs): add label slot for pane & function + vnode typed label
This commit is contained in:
parent
64b1715526
commit
826bf1dccb
@ -6,6 +6,8 @@
|
||||
|
||||
- `n-tabs` add `on-close` prop.
|
||||
- `n-tabs` add `on-add` prop.
|
||||
- `n-tabs` add `label` slot.
|
||||
- `n-tab-pane`'s `label` prop support render function & VNode.
|
||||
|
||||
## 2.9.0
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
- `n-tabs` 新增 `on-close` 属性
|
||||
- `n-tabs` 新增 `on-add` 属性
|
||||
- `n-tab-pane` 新增 `label` slot
|
||||
- `n-tab-pane` 的 `label` 属性支持渲染函数和 VNode
|
||||
|
||||
## 2.9.0
|
||||
|
||||
|
@ -7,6 +7,7 @@ export {
|
||||
getVNodeChildren,
|
||||
keysOf,
|
||||
render,
|
||||
render as Render,
|
||||
getFirstSlotVNode
|
||||
} from './vue'
|
||||
export type { MaybeArray } from './vue'
|
||||
|
@ -40,15 +40,22 @@ addable
|
||||
| closable | `boolean` | `false` | Whether to allow tab to close, Only works when tabs type is `'card'`. |
|
||||
| disabled | `boolean` | `false` | |
|
||||
| display-directive | `'if' \| 'show'` | `'if'` | The directive to use in conditionally rendering. 'if' will use 'v-if' and 'show' will use 'v-show'. When use show directive, the status of tab won't be reset after tab changes. |
|
||||
| label | `string` | `undefined` | |
|
||||
| label | `string \| VNode \| () => VNodeChild` | `undefined` | |
|
||||
| name | `string \| number` | required | |
|
||||
|
||||
## Slots
|
||||
|
||||
### Tabs, Tab Pane Slots
|
||||
### Tabs Slots
|
||||
|
||||
| Name | Parameters | Description |
|
||||
| ------- | ---------- | ----------- |
|
||||
| default | `()` | |
|
||||
| prefix | `()` | |
|
||||
| suffux | `()` | |
|
||||
|
||||
### Tab Pane Slots
|
||||
|
||||
| Name | Parameters | Description |
|
||||
| ------- | ---------- | ----------- |
|
||||
| default | `()` | |
|
||||
| label | `()` | |
|
||||
|
@ -41,15 +41,22 @@ line-debug
|
||||
| closable | `boolean` | `false` | 是否允许 tab 关闭,只在 tabs type 为 `'card'` 时生效 |
|
||||
| disabled | `boolean` | `false` | |
|
||||
| display-directive | `'if' \| 'show'` | `'if'` | 选择性渲染使用的指令。if 对应 v-if,show 对应 v-show,使用 show 的时候标签页状态切换后不会被重置 |
|
||||
| label | `string` | `undefined` | |
|
||||
| label | `string \| VNode \| () => VNodeChild` | `undefined` | |
|
||||
| name | `string \| number` | required | |
|
||||
|
||||
## Slots
|
||||
|
||||
### Tabs, Tab Pane Slots
|
||||
### Tabs
|
||||
|
||||
| 名称 | 参数 | 说明 |
|
||||
| ------- | ---- | ---- |
|
||||
| default | `()` | |
|
||||
| prefix | `()` | |
|
||||
| suffux | `()` | |
|
||||
|
||||
### Tab Pane Slots
|
||||
|
||||
| 名称 | 参数 | 说明 |
|
||||
| ------- | ---- | ---- |
|
||||
| default | `()` | |
|
||||
| label | `()` | |
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { h, defineComponent, inject, computed } from 'vue'
|
||||
import { NBaseClose, NBaseIcon } from '../../_internal'
|
||||
import { AddIcon } from '../../_internal/icons'
|
||||
import { NBaseClose, NBaseIcon } from '../../_internal'
|
||||
import { Render } from '../../_utils'
|
||||
import { tabsInjectionKey } from './interface'
|
||||
import { tabPaneProps } from './TabPane'
|
||||
|
||||
@ -60,7 +61,8 @@ export default defineComponent({
|
||||
label,
|
||||
value,
|
||||
mergedClosable,
|
||||
style
|
||||
style,
|
||||
$slots: { default: defaultSlot }
|
||||
} = this
|
||||
return (
|
||||
<div class={`${clsPrefix}-tabs-tab-wrapper`}>
|
||||
@ -90,8 +92,12 @@ export default defineComponent({
|
||||
default: () => <AddIcon />
|
||||
}}
|
||||
</NBaseIcon>
|
||||
) : defaultSlot ? (
|
||||
defaultSlot()
|
||||
) : typeof label === 'object' ? (
|
||||
label // VNode
|
||||
) : (
|
||||
label ?? name
|
||||
<Render render={label ?? name} />
|
||||
)}
|
||||
</span>
|
||||
{mergedClosable && this.type === 'card' ? (
|
||||
|
@ -1,17 +1,12 @@
|
||||
import {
|
||||
h,
|
||||
withDirectives,
|
||||
vShow,
|
||||
defineComponent,
|
||||
inject,
|
||||
PropType
|
||||
} from 'vue'
|
||||
import { h, defineComponent, inject, PropType, VNodeChild, VNode } from 'vue'
|
||||
import { throwError } from '../../_utils'
|
||||
import { tabsInjectionKey } from './interface'
|
||||
import type { ExtractPublicPropTypes } from '../../_utils'
|
||||
|
||||
export const tabPaneProps = {
|
||||
label: [String, Number] as PropType<string | number>,
|
||||
label: [String, Number, Object, Function] as PropType<
|
||||
string | number | VNode | (() => VNodeChild)
|
||||
>,
|
||||
name: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
required: true
|
||||
@ -39,22 +34,10 @@ export default defineComponent({
|
||||
throwError('tab-pane', '`n-tab-pane` must be placed inside `n-tabs`.')
|
||||
}
|
||||
return {
|
||||
mergedClsPrefix: NTab.mergedClsPrefixRef,
|
||||
type: NTab.typeRef,
|
||||
value: NTab.valueRef
|
||||
mergedClsPrefix: NTab.mergedClsPrefixRef
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { name } = this
|
||||
const useVShow = this.displayDirective === 'show'
|
||||
const show = this.value === name
|
||||
return useVShow || show
|
||||
? withDirectives(
|
||||
<div class={`${this.mergedClsPrefix}-tab-panel`} key={name}>
|
||||
{this.$slots}
|
||||
</div>,
|
||||
[[vShow, !useVShow || show]]
|
||||
)
|
||||
: null
|
||||
return <div class={`${this.mergedClsPrefix}-tab-panel`}>{this.$slots}</div>
|
||||
}
|
||||
})
|
||||
|
@ -10,7 +10,9 @@ import {
|
||||
toRef,
|
||||
ComponentPublicInstance,
|
||||
VNode,
|
||||
nextTick
|
||||
nextTick,
|
||||
withDirectives,
|
||||
vShow
|
||||
} from 'vue'
|
||||
import { VResizeObserver, VXScroll } from 'vueuc'
|
||||
import { throttle } from 'lodash-es'
|
||||
@ -205,7 +207,6 @@ export default defineComponent({
|
||||
} = entry
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const containerWidth = target.parentElement!.offsetWidth
|
||||
console.log(width, containerWidth)
|
||||
if (!addTabFixedRef.value) {
|
||||
if (containerWidth < width) {
|
||||
addTabFixedRef.value = true
|
||||
@ -365,7 +366,11 @@ export default defineComponent({
|
||||
leftPadded={
|
||||
index !== 0 && !mergedJustifyContent
|
||||
}
|
||||
/>
|
||||
>
|
||||
{{
|
||||
default: tabPaneVNode.children.label
|
||||
}}
|
||||
</Tab>
|
||||
)
|
||||
})}
|
||||
{!addTabFixed && addable && !isLine
|
||||
@ -419,12 +424,36 @@ export default defineComponent({
|
||||
<div class={`${mergedClsPrefix}-tabs-nav__suffix`}>{suffix}</div>
|
||||
) : null}
|
||||
</div>
|
||||
{children}
|
||||
{filterMapTabPanes(children, this.mergedValue)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
function filterMapTabPanes (
|
||||
tabPaneVNodes: VNode[],
|
||||
value: string | number | undefined
|
||||
): VNode[] {
|
||||
const children: VNode[] = []
|
||||
tabPaneVNodes.forEach((vNode) => {
|
||||
const { name, displayDirective } = vNode.props as {
|
||||
name: string | number
|
||||
displayDirective: 'show' | 'if' | undefined
|
||||
}
|
||||
const useVShow = displayDirective === 'show'
|
||||
const show = value === name
|
||||
if (vNode.key !== undefined) {
|
||||
vNode.key = name
|
||||
}
|
||||
if (useVShow) {
|
||||
children.push(withDirectives(vNode, [[vShow, show]]))
|
||||
} else if (show) {
|
||||
children.push(vNode)
|
||||
}
|
||||
})
|
||||
return children
|
||||
}
|
||||
|
||||
function createAddTag (addable: Addable, leftPadded: boolean): VNode {
|
||||
return (
|
||||
<Tab
|
||||
|
Loading…
Reference in New Issue
Block a user