mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-02-17 13:20:52 +08:00
feat(anchor): showRail, showBackground
This commit is contained in:
parent
bfd1c84852
commit
97ece8c8d6
@ -10,12 +10,10 @@ import {
|
|||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { getScrollParent, unwrapElement } from 'seemly'
|
import { getScrollParent, unwrapElement } from 'seemly'
|
||||||
import { useStyle } from '../../_mixins'
|
import { useStyle } from '../../_mixins'
|
||||||
import { warn } from '../../_utils'
|
import { warn, keysOf } from '../../_utils'
|
||||||
import style from './styles/index.cssr'
|
import style from './styles/index.cssr'
|
||||||
|
|
||||||
export default defineComponent({
|
export const affixProps = {
|
||||||
name: 'Affix',
|
|
||||||
props: {
|
|
||||||
listenTo: {
|
listenTo: {
|
||||||
type: [String, Object] as PropType<
|
type: [String, Object] as PropType<
|
||||||
string | (() => HTMLElement) | undefined
|
string | (() => HTMLElement) | undefined
|
||||||
@ -51,7 +49,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
default: undefined
|
default: undefined
|
||||||
}
|
}
|
||||||
},
|
} as const
|
||||||
|
|
||||||
|
export const affixPropKeys = keysOf(affixProps)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Affix',
|
||||||
|
props: affixProps,
|
||||||
setup (props) {
|
setup (props) {
|
||||||
useStyle('Affix', style)
|
useStyle('Affix', style)
|
||||||
const scrollElementRef = ref<HTMLElement | null>(null)
|
const scrollElementRef = ref<HTMLElement | null>(null)
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
# Basic
|
# Basic
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div>
|
<n-space style="margin-bottom: 12px;">
|
||||||
<n-anchor>
|
<n-switch v-model:value="showRail" /> Show Rail
|
||||||
|
<n-switch v-model:value="showBackground" /> Show Background
|
||||||
|
</n-space>
|
||||||
|
<n-anchor>
|
||||||
<n-anchor-link title="Demos" href="#Demos">
|
<n-anchor-link title="Demos" href="#Demos">
|
||||||
<n-anchor-link title="Basic" href="#basic" />
|
<n-anchor-link title="Basic" href="#basic" />
|
||||||
<n-anchor-link title="Ignore-Gap" href="#ignore-gap" />
|
<n-anchor-link title="Ignore-Gap" href="#ignore-gap" />
|
||||||
@ -10,6 +13,18 @@
|
|||||||
<n-anchor-link title="Scroll To" href="#scrollto" />
|
<n-anchor-link title="Scroll To" href="#scrollto" />
|
||||||
</n-anchor-link>
|
</n-anchor-link>
|
||||||
<n-anchor-link title="Props" href="#Props" />
|
<n-anchor-link title="Props" href="#Props" />
|
||||||
</n-anchor>
|
</n-anchor>
|
||||||
</div>
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup () {
|
||||||
|
return {
|
||||||
|
showRail: ref(true),
|
||||||
|
showBackground: ref(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
@ -11,7 +11,6 @@ basic
|
|||||||
ignore-gap
|
ignore-gap
|
||||||
affix
|
affix
|
||||||
scrollto
|
scrollto
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Props
|
## Props
|
||||||
@ -22,6 +21,8 @@ scrollto
|
|||||||
| bound | `number` | `12` | |
|
| bound | `number` | `12` | |
|
||||||
| ignore-gap | `boolean` | `false` | If set to `true`, it will be displayed on the exact href |
|
| ignore-gap | `boolean` | `false` | If set to `true`, it will be displayed on the exact href |
|
||||||
| listen-to | `string \| HTMLElement` | `undefined` | The scrolling element to listen scrolling. If not set it will listen to the nearest scrollable ascendant element. |
|
| listen-to | `string \| HTMLElement` | `undefined` | The scrolling element to listen scrolling. If not set it will listen to the nearest scrollable ascendant element. |
|
||||||
|
| show-rail | `boolean` | `true` | Whether to show the sider rail. |
|
||||||
|
| show-background | `boolean` | `true` | Whether to show background of links. |
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
# 基础用法
|
# 基础用法
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div>
|
<n-space style="margin-bottom: 12px;">
|
||||||
<n-anchor>
|
<n-switch v-model:value="showRail" /> 展示轨道
|
||||||
|
<n-switch v-model:value="showBackground" /> 展示背景
|
||||||
|
</n-space>
|
||||||
|
<n-anchor :show-rail="showRail" :show-background="showBackground">
|
||||||
<n-anchor-link title="演示" href="#演示">
|
<n-anchor-link title="演示" href="#演示">
|
||||||
<n-anchor-link title="基础用法" href="#basic" />
|
<n-anchor-link title="基础用法" href="#basic" />
|
||||||
<n-anchor-link title="忽略间隔" href="#ignore-gap" />
|
<n-anchor-link title="忽略间隔" href="#ignore-gap" />
|
||||||
@ -10,6 +13,18 @@
|
|||||||
<n-anchor-link title="滚动到" href="#scrollto" />
|
<n-anchor-link title="滚动到" href="#scrollto" />
|
||||||
</n-anchor-link>
|
</n-anchor-link>
|
||||||
<n-anchor-link title="Props" href="#Props" />
|
<n-anchor-link title="Props" href="#Props" />
|
||||||
</n-anchor>
|
</n-anchor>
|
||||||
</div>
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup () {
|
||||||
|
return {
|
||||||
|
showRail: ref(true),
|
||||||
|
showBackground: ref(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
@ -21,6 +21,8 @@ scrollto
|
|||||||
| bound | `number` | `12` | |
|
| bound | `number` | `12` | |
|
||||||
| ignore-gap | `boolean` | `false` | 如果设定为 `true`, 导航将显示在准确的 href 区域 |
|
| ignore-gap | `boolean` | `false` | 如果设定为 `true`, 导航将显示在准确的 href 区域 |
|
||||||
| listen-to | `string \| HTMLElement` | `undefined` | 需要监听滚动的元素,如果未设定则会监听最近的可滚动祖先元素 |
|
| listen-to | `string \| HTMLElement` | `undefined` | 需要监听滚动的元素,如果未设定则会监听最近的可滚动祖先元素 |
|
||||||
|
| show-rail | `boolean` | `true` | 是否展示侧面的轨道 |
|
||||||
|
| show-background | `boolean` | `true` | 是否展示 link 的背景 |
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { h, defineComponent, computed, ref, CSSProperties, PropType } from 'vue'
|
import { h, defineComponent, computed, ref, CSSProperties } from 'vue'
|
||||||
import { NAffix } from '../../affix'
|
import { NAffix } from '../../affix'
|
||||||
|
import { affixProps, affixPropKeys } from '../../affix/src/Affix'
|
||||||
import { useTheme } from '../../_mixins'
|
import { useTheme } from '../../_mixins'
|
||||||
import type { ThemeProps } from '../../_mixins'
|
import type { ThemeProps } from '../../_mixins'
|
||||||
|
import { keep } from '../../_utils'
|
||||||
import { anchorLight } from '../styles'
|
import { anchorLight } from '../styles'
|
||||||
import type { AnchorTheme } from '../styles'
|
import type { AnchorTheme } from '../styles'
|
||||||
import style from './styles/index.cssr'
|
import style from './styles/index.cssr'
|
||||||
import NBaseAnchor from './BaseAnchor'
|
import NBaseAnchor, { baseAnchorProps, baseAnchorPropKeys } from './BaseAnchor'
|
||||||
import type { BaseAnchorRef } from './BaseAnchor'
|
import type { BaseAnchorRef } from './BaseAnchor'
|
||||||
|
|
||||||
export interface AnchorRef {
|
export interface AnchorRef {
|
||||||
@ -16,52 +18,12 @@ export default defineComponent({
|
|||||||
name: 'Anchor',
|
name: 'Anchor',
|
||||||
props: {
|
props: {
|
||||||
...(useTheme.props as ThemeProps<AnchorTheme>),
|
...(useTheme.props as ThemeProps<AnchorTheme>),
|
||||||
top: {
|
|
||||||
type: Number,
|
|
||||||
default: undefined
|
|
||||||
},
|
|
||||||
affix: {
|
affix: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
position: {
|
...affixProps,
|
||||||
type: String,
|
...baseAnchorProps
|
||||||
default: undefined
|
|
||||||
},
|
|
||||||
bottom: {
|
|
||||||
type: Number,
|
|
||||||
default: undefined
|
|
||||||
},
|
|
||||||
offsetBottom: {
|
|
||||||
type: Number,
|
|
||||||
default: undefined
|
|
||||||
},
|
|
||||||
offsetTop: {
|
|
||||||
type: Number,
|
|
||||||
default: undefined
|
|
||||||
},
|
|
||||||
bound: {
|
|
||||||
type: Number,
|
|
||||||
default: 12
|
|
||||||
},
|
|
||||||
ignoreGap: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
listenTo: {
|
|
||||||
type: [String, Object] as PropType<
|
|
||||||
string | (() => HTMLElement) | undefined
|
|
||||||
>,
|
|
||||||
default: undefined
|
|
||||||
},
|
|
||||||
// deprecated
|
|
||||||
target: {
|
|
||||||
type: Function as PropType<(() => HTMLElement) | undefined>,
|
|
||||||
validator: () => {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
default: undefined
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
setup (props) {
|
setup (props) {
|
||||||
const themeRef = useTheme('Anchor', 'Anchor', style, anchorLight, props)
|
const themeRef = useTheme('Anchor', 'Anchor', style, anchorLight, props)
|
||||||
@ -105,10 +67,7 @@ export default defineComponent({
|
|||||||
<NBaseAnchor
|
<NBaseAnchor
|
||||||
ref="anchorRef"
|
ref="anchorRef"
|
||||||
style={this.cssVars as CSSProperties}
|
style={this.cssVars as CSSProperties}
|
||||||
listenTo={this.listenTo}
|
{...keep(this, baseAnchorPropKeys)}
|
||||||
bound={this.bound}
|
|
||||||
target={this.target}
|
|
||||||
ignoreGap={this.ignoreGap}
|
|
||||||
>
|
>
|
||||||
{this.$slots}
|
{this.$slots}
|
||||||
</NBaseAnchor>
|
</NBaseAnchor>
|
||||||
@ -116,15 +75,7 @@ export default defineComponent({
|
|||||||
return !this.affix ? (
|
return !this.affix ? (
|
||||||
anchorNode
|
anchorNode
|
||||||
) : (
|
) : (
|
||||||
<NAffix
|
<NAffix {...keep(this, affixPropKeys)}>
|
||||||
listenTo={this.listenTo}
|
|
||||||
top={this.top}
|
|
||||||
bottom={this.bottom}
|
|
||||||
offsetTop={this.offsetTop}
|
|
||||||
offsetBottom={this.offsetBottom}
|
|
||||||
position={this.position}
|
|
||||||
target={this.target}
|
|
||||||
>
|
|
||||||
{{ default: () => anchorNode }}
|
{{ default: () => anchorNode }}
|
||||||
</NAffix>
|
</NAffix>
|
||||||
)
|
)
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { getScrollParent, unwrapElement } from 'seemly'
|
import { getScrollParent, unwrapElement } from 'seemly'
|
||||||
import { onFontsReady } from 'vooks'
|
import { onFontsReady } from 'vooks'
|
||||||
import { warn } from '../../_utils'
|
import { warn, keysOf } from '../../_utils'
|
||||||
import type { AnchorInjection } from './Link'
|
import type { AnchorInjection } from './Link'
|
||||||
|
|
||||||
export interface BaseAnchorRef {
|
export interface BaseAnchorRef {
|
||||||
@ -36,10 +36,16 @@ function getOffset (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export const baseAnchorProps = {
|
||||||
name: 'BaseAnchor',
|
|
||||||
props: {
|
|
||||||
listenTo: [String, Object] as PropType<string | (() => HTMLElement)>,
|
listenTo: [String, Object] as PropType<string | (() => HTMLElement)>,
|
||||||
|
showRail: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
showBackground: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
bound: {
|
bound: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 12
|
default: 12
|
||||||
@ -53,16 +59,19 @@ export default defineComponent({
|
|||||||
type: Function as PropType<(() => HTMLElement) | undefined>,
|
type: Function as PropType<(() => HTMLElement) | undefined>,
|
||||||
validator: () => {
|
validator: () => {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
warn(
|
warn('anchor', '`target` is deprecated, please use`listen-to` instead.')
|
||||||
'anchor',
|
|
||||||
'`target` is deprecated, please use`listen-to` instead.'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
default: undefined
|
default: undefined
|
||||||
}
|
}
|
||||||
},
|
} as const
|
||||||
|
|
||||||
|
export const baseAnchorPropKeys = keysOf(baseAnchorProps)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'BaseAnchor',
|
||||||
|
props: baseAnchorProps,
|
||||||
setup (props) {
|
setup (props) {
|
||||||
let scrollElement: HTMLElement | null
|
let scrollElement: HTMLElement | null
|
||||||
const collectedLinkHrefs: string[] = markRaw([])
|
const collectedLinkHrefs: string[] = markRaw([])
|
||||||
@ -111,10 +120,10 @@ export default defineComponent({
|
|||||||
const { value: barEl } = barRef
|
const { value: barEl } = barRef
|
||||||
const { value: slotEl } = slotRef
|
const { value: slotEl } = slotRef
|
||||||
const { value: selfEl } = selfRef
|
const { value: selfEl } = selfRef
|
||||||
if (!selfEl || !barEl || !slotEl) return
|
if (!selfEl || !barEl) return
|
||||||
if (!transition) {
|
if (!transition) {
|
||||||
barEl.style.transition = 'none'
|
barEl.style.transition = 'none'
|
||||||
slotEl.style.transition = 'none'
|
if (slotEl) slotEl.style.transition = 'none'
|
||||||
}
|
}
|
||||||
const { offsetHeight, offsetWidth } = linkTitleEl
|
const { offsetHeight, offsetWidth } = linkTitleEl
|
||||||
const {
|
const {
|
||||||
@ -129,15 +138,17 @@ export default defineComponent({
|
|||||||
const offsetLeft = linkTitleClientLeft - anchorClientLeft
|
const offsetLeft = linkTitleClientLeft - anchorClientLeft
|
||||||
barEl.style.top = `${offsetTop}px`
|
barEl.style.top = `${offsetTop}px`
|
||||||
barEl.style.height = `${offsetHeight}px`
|
barEl.style.height = `${offsetHeight}px`
|
||||||
|
if (slotEl) {
|
||||||
slotEl.style.top = `${offsetTop}px`
|
slotEl.style.top = `${offsetTop}px`
|
||||||
slotEl.style.height = `${offsetHeight}px`
|
slotEl.style.height = `${offsetHeight}px`
|
||||||
slotEl.style.maxWidth = `${offsetWidth + offsetLeft}px`
|
slotEl.style.maxWidth = `${offsetWidth + offsetLeft}px`
|
||||||
|
}
|
||||||
void barEl.offsetHeight
|
void barEl.offsetHeight
|
||||||
void slotEl.offsetHeight
|
if (slotEl) void slotEl.offsetHeight
|
||||||
|
|
||||||
if (!transition) {
|
if (!transition) {
|
||||||
barEl.style.transition = ''
|
barEl.style.transition = ''
|
||||||
slotEl.style.transition = ''
|
if (slotEl) slotEl.style.transition = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function setActiveHref (href: string, transition = true): void {
|
function setActiveHref (href: string, transition = true): void {
|
||||||
@ -286,8 +297,14 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div class="n-anchor" ref="selfRef">
|
<div
|
||||||
|
class={['n-anchor', this.showRail && 'n-anchor--show-rail']}
|
||||||
|
ref="selfRef"
|
||||||
|
>
|
||||||
|
{this.showRail && this.showBackground ? (
|
||||||
<div ref="slotRef" class="n-anchor-link-background" />
|
<div ref="slotRef" class="n-anchor-link-background" />
|
||||||
|
) : null}
|
||||||
|
{this.showRail ? (
|
||||||
<div class="n-anchor-rail">
|
<div class="n-anchor-rail">
|
||||||
<div
|
<div
|
||||||
ref="barRef"
|
ref="barRef"
|
||||||
@ -299,6 +316,7 @@ export default defineComponent({
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
) : null}
|
||||||
{renderSlot(this.$slots, 'default')}
|
{renderSlot(this.$slots, 'default')}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { c, cE, cB, cM } from '../../../_utils/cssr'
|
import { c, cE, cB, cM, cNotM } from '../../../_utils/cssr'
|
||||||
|
|
||||||
// vars:
|
// vars:
|
||||||
// --link-color
|
// --link-color
|
||||||
@ -51,15 +51,16 @@ export default cB('anchor', `
|
|||||||
cM('active', {
|
cM('active', {
|
||||||
backgroundColor: 'var(--rail-color-active)'
|
backgroundColor: 'var(--rail-color-active)'
|
||||||
})
|
})
|
||||||
|
])
|
||||||
]),
|
]),
|
||||||
c('+', [
|
cNotM('show-rail', [
|
||||||
|
c('>', [
|
||||||
cB('anchor-link', {
|
cB('anchor-link', {
|
||||||
marginTop: 0
|
paddingLeft: 0
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
cB('anchor-link', `
|
cB('anchor-link', `
|
||||||
margin-top: .5em;
|
|
||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
position: relative;
|
position: relative;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
@ -68,10 +69,10 @@ export default cB('anchor', `
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`, [
|
`, [
|
||||||
c('+', [
|
c('+, >', [
|
||||||
cB('anchor-link', {
|
cB('anchor-link', `
|
||||||
paddingLeft: '16px'
|
margin-top: .5em;
|
||||||
})
|
`)
|
||||||
]),
|
]),
|
||||||
cE('title', `
|
cE('title', `
|
||||||
outline: none;
|
outline: none;
|
||||||
|
3
vue3.md
3
vue3.md
@ -22,6 +22,9 @@
|
|||||||
- `target` => `listen-to`
|
- `target` => `listen-to`
|
||||||
- [x] alert
|
- [x] alert
|
||||||
- [x] anchor
|
- [x] anchor
|
||||||
|
- new
|
||||||
|
- `show-rail` props
|
||||||
|
- `show-background` props
|
||||||
- deprecate
|
- deprecate
|
||||||
- `target` => `listen-to`
|
- `target` => `listen-to`
|
||||||
- [x] auto-complete
|
- [x] auto-complete
|
||||||
|
Loading…
Reference in New Issue
Block a user