feat(slider): add render function support for marks prop (#6008)

* feat(`n-slider`): add render function support for `marks` prop

* chore: update `marks` prop type to support render function

---------

Co-authored-by: 07akioni <07akioni2@gmail.com>
This commit is contained in:
jahnli 2024-07-21 23:12:15 +08:00 committed by GitHub
parent e03f00ab87
commit b0439c8a15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 120 additions and 7 deletions

View File

@ -17,6 +17,7 @@
- `n-date-picker` adds `clear` `now` `confirm` slot, closes [#6013](https://github.com/tusen-ai/naive-ui/issues/6013).
- `n-upload` adds `on-retry` prop, closes [#6031](https://github.com/tusen-ai/naive-ui/issues/6031)
- Adds `n-highlight` component.
- `n-slider` `marks` prop to support render function, closes [#5967](https://github.com/tusen-ai/naive-ui/issues/5967)
## 2.39.0

View File

@ -17,6 +17,7 @@
- `n-date-picker` 新增 `clear` `now` `confirm` 插槽,关闭 [#6013](https://github.com/tusen-ai/naive-ui/issues/6013)
- `n-upload` 新增 `on-retry`属性,关闭 [#6031](https://github.com/tusen-ai/naive-ui/issues/6031)
- 新增 `n-highlight` 组件
- `n-slider` `marks` 支持渲染函数,关闭 [#5967](https://github.com/tusen-ai/naive-ui/issues/5967)
## 2.39.0

View File

@ -0,0 +1,53 @@
<markdown>
# Custom Mark
You can use `marks` prop to customize handle button.
</markdown>
<template>
<n-space style="height: 300px; justify-content: space-evenly">
<n-slider v-model:value="value" :marks="marks" vertical range />
<n-slider v-model:value="value" :marks="customMarks" vertical range />
</n-space>
</template>
<script lang="ts">
import { defineComponent, ref, h } from 'vue'
import Temperature16Regular from '@vicons/fluent/Temperature16Regular'
import { NIcon } from '../../../icon'
import { NFlex } from '../../../flex'
export default defineComponent({
setup () {
const renderMark = (value: number, color: string) => {
return h(
NFlex,
{ style: { width: '120px' } },
{
default: () => [
h(NIcon, { size: 24, color, component: Temperature16Regular }),
h('span', { style: { color } }, `${value}°C`)
]
}
)
}
return {
value: ref([20, 70]),
marks: {
0: '0°C',
20: '20°C',
60: '60°C',
100: '100°C'
},
customMarks: {
0: () => renderMark(0, '#0048BA'),
20: () => renderMark(20, '#00BFFF'),
60: () => renderMark(60, '#FFA500'),
100: () => renderMark(100, '#FF4500')
}
}
}
})
</script>

View File

@ -17,6 +17,7 @@ vertical.vue
show-tooltip.vue
multiple-debug.vue
custom-thumb.vue
custom-marks.vue
```
## API
@ -29,7 +30,7 @@ custom-thumb.vue
| disabled | `boolean` | `false` | Whether the slider is disabled. | |
| format-tooltip | `(value: number) => string \| number` | `undefined` | Format tooltip. | |
| keyboard | `boolean` | `true` | Whether the slider can be controlled keyboard. | 2.33.0 |
| marks | `{ [markValue: number]: string }` | `undefined` | Marks of the slider. | |
| marks | `{ [markValue: number]: string \| (() => VNodeChild) }` | `undefined` | Marks of the slider, Render function since NEXT_VERSION. | |
| max | `number` | `100` | Max value of the slider. | |
| min | `number` | `0` | Min value of the slider. | |
| placement | `'top-start' \| 'top' \| 'top-end' \| 'right-start' \| 'right' \| 'right-end' \| 'bottom-start' \| 'bottom' \| 'bottom-end' \| 'left-start' \| 'left' \| 'left-end'` | `undefined` | Tooltip's placement | 2.25.0 |

View File

@ -0,0 +1,53 @@
<markdown>
# 自定义标记
可以使用 `marks` 插槽自定义刻度
</markdown>
<template>
<n-space style="height: 300px; justify-content: space-evenly">
<n-slider v-model:value="value" :marks="marks" vertical range />
<n-slider v-model:value="value" :marks="customMarks" vertical range />
</n-space>
</template>
<script lang="ts">
import { defineComponent, ref, h } from 'vue'
import Temperature16Regular from '@vicons/fluent/Temperature16Regular'
import { NIcon } from '../../../icon'
import { NFlex } from '../../../flex'
export default defineComponent({
setup () {
const renderMark = (value: number, color: string) => {
return h(
NFlex,
{ style: { width: '120px' } },
{
default: () => [
h(NIcon, { size: 24, color, component: Temperature16Regular }),
h('span', { style: { color } }, `${value}°C`)
]
}
)
}
return {
value: ref([20, 70]),
marks: {
0: '0°C',
20: '20°C',
60: '60°C',
100: '100°C'
},
customMarks: {
0: () => renderMark(0, '#0048BA'),
20: () => renderMark(20, '#00BFFF'),
60: () => renderMark(60, '#FFA500'),
100: () => renderMark(100, '#FF4500')
}
}
}
})
</script>

View File

@ -17,6 +17,7 @@ vertical.vue
show-tooltip.vue
multiple-debug.vue
custom-thumb.vue
custom-marks.vue
keyboard-debug.vue
```
@ -30,7 +31,7 @@ keyboard-debug.vue
| disabled | `boolean` | `false` | 是否禁用 | |
| format-tooltip | `(value: number) => string \| number` | `undefined` | 格式化 tooltip | |
| keyboard | `boolean` | `true` | 是否可键盘控制 | 2.33.0 |
| marks | `{ [markValue: number]: string }` | `undefined` | Slider 上的标记 | |
| marks | `{ [markValue: number]: string \| (() => VNodeChild) }` | `undefined` | Slider 上的标记NEXT_VERSION 支持 render 函数 | |
| max | `number` | `100` | 最大值 | |
| min | `number` | `0` | 最小值 | |
| placement | `'top-start' \| 'top' \| 'top-end' \| 'right-start' \| 'right' \| 'right-end' \| 'bottom-start' \| 'bottom' \| 'bottom-end' \| 'left-start' \| 'left' \| 'left-end'` | `undefined` | Tooltip 的弹出位置 | 2.25.0 |

View File

@ -2,6 +2,7 @@ import {
type CSSProperties,
type ComponentPublicInstance,
type PropType,
type VNodeChild,
Transition,
computed,
defineComponent,
@ -56,7 +57,7 @@ export const sliderProps = {
type: [Number, Array] as PropType<number | number[]>,
default: 0
},
marks: Object as PropType<Record<string, string>>,
marks: Object as PropType<Record<string, string | (() => VNodeChild)>>,
disabled: {
type: Boolean as PropType<boolean | undefined>,
default: undefined
@ -205,7 +206,8 @@ export default defineComponent({
const markInfosRef = computed(() => {
const mergedMarks: Array<{
active: boolean
label: string
label: string | (() => VNodeChild)
key: number
style: CSSProperties
}> = []
const { marks } = props
@ -226,6 +228,7 @@ export default defineComponent({
const num = Number(key)
mergedMarks.push({
active: isActive(num),
key: num,
label: marks[key],
style: {
[styleDirection]: `${valueToPercentage(num)}%`
@ -718,7 +721,7 @@ export default defineComponent({
>
{this.markInfos.map(mark => (
<div
key={mark.label}
key={mark.key}
class={[
`${mergedClsPrefix}-slider-dot`,
{
@ -843,11 +846,11 @@ export default defineComponent({
<div class={`${mergedClsPrefix}-slider-marks`}>
{this.markInfos.map(mark => (
<div
key={mark.label}
key={mark.key}
class={`${mergedClsPrefix}-slider-mark`}
style={mark.style}
>
{mark.label}
{typeof mark.label === 'function' ? mark.label() : mark.label}
</div>
))}
</div>