feat(anchor): add direction action (#6447)
* refactor(anchor): direction show * refactor(anchor): update anchor css * feat(anchor): update demo * test(anchor): update demo test snap * feat(anchor): update docs * Update index.zh-CN.md * Update index.en-US.md --------- Co-authored-by: tangjinzhou <415800467@qq.com>pull/6514/head
parent
de00607dc7
commit
8932aff13f
|
@ -1,5 +1,6 @@
|
||||||
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
|
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
|
||||||
import {
|
import {
|
||||||
|
watch,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
nextTick,
|
nextTick,
|
||||||
onBeforeUnmount,
|
onBeforeUnmount,
|
||||||
|
@ -9,6 +10,7 @@ import {
|
||||||
ref,
|
ref,
|
||||||
computed,
|
computed,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import addEventListener from '../vc-util/Dom/addEventListener';
|
import addEventListener from '../vc-util/Dom/addEventListener';
|
||||||
import Affix from '../affix';
|
import Affix from '../affix';
|
||||||
|
@ -20,6 +22,8 @@ import useStyle from './style';
|
||||||
import type { AnchorLinkProps } from './AnchorLink';
|
import type { AnchorLinkProps } from './AnchorLink';
|
||||||
import AnchorLink from './AnchorLink';
|
import AnchorLink from './AnchorLink';
|
||||||
import type { Key } from '../_util/type';
|
import type { Key } from '../_util/type';
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
import devWarning from '../vc-util/devWarning';
|
||||||
|
|
||||||
export interface AnchorLinkItemProps extends AnchorLinkProps {
|
export interface AnchorLinkItemProps extends AnchorLinkProps {
|
||||||
key: Key;
|
key: Key;
|
||||||
|
@ -27,6 +31,9 @@ export interface AnchorLinkItemProps extends AnchorLinkProps {
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
children?: AnchorLinkItemProps[];
|
children?: AnchorLinkItemProps[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AnchorDirection = 'vertical' | 'horizontal';
|
||||||
|
|
||||||
function getDefaultContainer() {
|
function getDefaultContainer() {
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +80,7 @@ export const anchorProps = () => ({
|
||||||
type: Array as PropType<AnchorLinkItemProps[]>,
|
type: Array as PropType<AnchorLinkItemProps[]>,
|
||||||
default: undefined as AnchorLinkItemProps[],
|
default: undefined as AnchorLinkItemProps[],
|
||||||
},
|
},
|
||||||
|
direction: PropTypes.oneOf(['vertical', 'horizontal'] as AnchorDirection[]).def('vertical'),
|
||||||
onChange: Function as PropType<(currentActiveLink: string) => void>,
|
onChange: Function as PropType<(currentActiveLink: string) => void>,
|
||||||
onClick: Function as PropType<(e: MouseEvent, link: { title: any; href: string }) => void>,
|
onClick: Function as PropType<(e: MouseEvent, link: { title: any; href: string }) => void>,
|
||||||
});
|
});
|
||||||
|
@ -93,6 +101,24 @@ export default defineComponent({
|
||||||
props: anchorProps(),
|
props: anchorProps(),
|
||||||
setup(props, { emit, attrs, slots, expose }) {
|
setup(props, { emit, attrs, slots, expose }) {
|
||||||
const { prefixCls, getTargetContainer, direction } = useConfigInject('anchor', props);
|
const { prefixCls, getTargetContainer, direction } = useConfigInject('anchor', props);
|
||||||
|
const anchorDirection = computed(() => props.direction ?? 'vertical');
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
devWarning(
|
||||||
|
typeof slots.default !== 'function',
|
||||||
|
'Anchor',
|
||||||
|
'`Anchor children` is deprecated. Please use `items` instead.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
devWarning(
|
||||||
|
!(anchorDirection.value === 'horizontal' && props.items?.some(n => 'children' in n)),
|
||||||
|
'Anchor',
|
||||||
|
'`Anchor items#children` is not supported when `Anchor` direction is horizontal.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const spanLinkNode = ref<HTMLSpanElement>(null);
|
const spanLinkNode = ref<HTMLSpanElement>(null);
|
||||||
const anchorRef = ref();
|
const anchorRef = ref();
|
||||||
const state = reactive<AnchorState>({
|
const state = reactive<AnchorState>({
|
||||||
|
@ -184,12 +210,21 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateInk = () => {
|
const updateInk = () => {
|
||||||
const linkNode = anchorRef.value.getElementsByClassName(
|
const linkNode = anchorRef.value.querySelector(`.${prefixCls.value}-link-title-active`);
|
||||||
`${prefixCls.value}-link-title-active`,
|
|
||||||
)[0];
|
|
||||||
if (linkNode && spanLinkNode.value) {
|
if (linkNode && spanLinkNode.value) {
|
||||||
spanLinkNode.value.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2}px`;
|
const horizontalAnchor = anchorDirection.value === 'horizontal';
|
||||||
spanLinkNode.value.style.height = `${linkNode.clientHeight}px`;
|
spanLinkNode.value.style.top = horizontalAnchor
|
||||||
|
? ''
|
||||||
|
: `${linkNode.offsetTop + linkNode.clientHeight / 2}px`;
|
||||||
|
spanLinkNode.value.style.height = horizontalAnchor ? '' : `${linkNode.clientHeight}px`;
|
||||||
|
spanLinkNode.value.style.left = horizontalAnchor ? `${linkNode.offsetLeft}px` : '';
|
||||||
|
spanLinkNode.value.style.width = horizontalAnchor ? `${linkNode.clientWidth}px` : '';
|
||||||
|
if (horizontalAnchor) {
|
||||||
|
scrollIntoView(linkNode, {
|
||||||
|
scrollMode: 'if-needed',
|
||||||
|
block: 'nearest',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -210,6 +245,7 @@ export default defineComponent({
|
||||||
handleClick: (e, info) => {
|
handleClick: (e, info) => {
|
||||||
emit('click', e, info);
|
emit('click', e, info);
|
||||||
},
|
},
|
||||||
|
direction: anchorDirection,
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -237,23 +273,31 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
updateInk();
|
updateInk();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch([anchorDirection, getCurrentAnchor, state.links, activeLink], () => {
|
||||||
|
updateInk();
|
||||||
|
});
|
||||||
|
|
||||||
const createNestedLink = (options?: AnchorLinkItemProps[]) =>
|
const createNestedLink = (options?: AnchorLinkItemProps[]) =>
|
||||||
Array.isArray(options)
|
Array.isArray(options)
|
||||||
? options.map(item => (
|
? options.map(item => (
|
||||||
<AnchorLink {...item} key={item.key}>
|
<AnchorLink {...item} key={item.key}>
|
||||||
{createNestedLink(item.children)}
|
{anchorDirection.value === 'vertical' ? createNestedLink(item.children) : null}
|
||||||
</AnchorLink>
|
</AnchorLink>
|
||||||
))
|
))
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const { offsetTop, affix, showInkInFixed } = props;
|
const { offsetTop, affix, showInkInFixed } = props;
|
||||||
const pre = prefixCls.value;
|
const pre = prefixCls.value;
|
||||||
const inkClass = classNames(`${pre}-ink-ball`, {
|
const inkClass = classNames(`${pre}-ink`, {
|
||||||
[`${pre}-ink-ball-visible`]: activeLink.value,
|
[`${pre}-ink-visible`]: activeLink.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
const wrapperClass = classNames(hashId.value, props.wrapperClass, `${pre}-wrapper`, {
|
const wrapperClass = classNames(hashId.value, props.wrapperClass, `${pre}-wrapper`, {
|
||||||
|
[`${pre}-wrapper-horizontal`]: anchorDirection.value === 'horizontal',
|
||||||
[`${pre}-rtl`]: direction.value === 'rtl',
|
[`${pre}-rtl`]: direction.value === 'rtl',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -268,9 +312,7 @@ export default defineComponent({
|
||||||
const anchorContent = (
|
const anchorContent = (
|
||||||
<div class={wrapperClass} style={wrapperStyle} ref={anchorRef}>
|
<div class={wrapperClass} style={wrapperStyle} ref={anchorRef}>
|
||||||
<div class={anchorClass}>
|
<div class={anchorClass}>
|
||||||
<div class={`${pre}-ink`}>
|
<span class={inkClass} ref={spanLinkNode} />
|
||||||
<span class={inkClass} ref={spanLinkNode} />
|
|
||||||
</div>
|
|
||||||
{Array.isArray(props.items) ? createNestedLink(props.items) : slots.default?.()}
|
{Array.isArray(props.items) ? createNestedLink(props.items) : slots.default?.()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,27 +2,19 @@
|
||||||
|
|
||||||
exports[`renders ./components/anchor/demo/basic.vue correctly 1`] = `
|
exports[`renders ./components/anchor/demo/basic.vue correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div class="">
|
<!---->
|
||||||
<div class="ant-anchor-wrapper" style="max-height: 100vh;">
|
<div class="css-dev-only-do-not-override-1tii49m">
|
||||||
<div class="ant-anchor">
|
<div class="css-dev-only-do-not-override-1tii49m ant-anchor-wrapper" style="max-height: 100vh;">
|
||||||
<div class="ant-anchor-ink"><span class="ant-anchor-ink-ball"></span></div>
|
<div class="ant-anchor"><span class="ant-anchor-ink"></span>
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#part-1" title="Part 1">Part 1</a>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-static" title="Static demo">Static demo</a>
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#part-2" title="Part 2">Part 2</a>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo with Target" target="_blank">Basic demo with Target</a>
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#part-3" title="Part 3">Part 3</a>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#API" title="API">API</a>
|
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#Anchor-Props" title="Anchor Props">Anchor Props</a>
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#Link-Props" title="Link Props">Link Props</a>
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,9 +22,8 @@ exports[`renders ./components/anchor/demo/basic.vue correctly 1`] = `
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/anchor/demo/customizeHighlight.vue correctly 1`] = `
|
exports[`renders ./components/anchor/demo/customizeHighlight.vue correctly 1`] = `
|
||||||
<div class="ant-anchor-wrapper" style="max-height: 100vh;">
|
<div class="css-dev-only-do-not-override-1tii49m ant-anchor-wrapper" style="max-height: 100vh;">
|
||||||
<div class="ant-anchor ant-anchor-fixed">
|
<div class="ant-anchor ant-anchor-fixed"><span class="ant-anchor-ink"></span>
|
||||||
<div class="ant-anchor-ink"><span class="ant-anchor-ink-ball"></span></div>
|
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,10 +42,41 @@ exports[`renders ./components/anchor/demo/customizeHighlight.vue correctly 1`] =
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`renders ./components/anchor/demo/horizontal.vue correctly 1`] = `
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<!---->
|
||||||
|
<div class="css-dev-only-do-not-override-1tii49m">
|
||||||
|
<div class="css-dev-only-do-not-override-1tii49m ant-anchor-wrapper ant-anchor-wrapper-horizontal" style="max-height: 100vh;">
|
||||||
|
<div class="ant-anchor"><span class="ant-anchor-ink"></span>
|
||||||
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#horizontally-part-1" title="Part 1">Part 1</a>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#horizontally-part-2" title="Part 2">Part 2</a>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#horizontally-part-3" title="Part 3">Part 3</a>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#horizontally-part-4" title="Part 4">Part 4</a>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#horizontally-part-5" title="Part 5">Part 5</a>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#horizontally-part-6" title="Part 6">Part 6</a>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/anchor/demo/onChange.vue correctly 1`] = `
|
exports[`renders ./components/anchor/demo/onChange.vue correctly 1`] = `
|
||||||
<div class="ant-anchor-wrapper" style="max-height: 100vh;">
|
<div class="css-dev-only-do-not-override-1tii49m ant-anchor-wrapper" style="max-height: 100vh;">
|
||||||
<div class="ant-anchor ant-anchor-fixed">
|
<div class="ant-anchor ant-anchor-fixed"><span class="ant-anchor-ink"></span>
|
||||||
<div class="ant-anchor-ink"><span class="ant-anchor-ink-ball"></span></div>
|
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
|
@ -74,9 +96,8 @@ exports[`renders ./components/anchor/demo/onChange.vue correctly 1`] = `
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/anchor/demo/onClick.vue correctly 1`] = `
|
exports[`renders ./components/anchor/demo/onClick.vue correctly 1`] = `
|
||||||
<div class="ant-anchor-wrapper" style="max-height: 100vh;">
|
<div class="css-dev-only-do-not-override-1tii49m ant-anchor-wrapper" style="max-height: 100vh;">
|
||||||
<div class="ant-anchor ant-anchor-fixed">
|
<div class="ant-anchor ant-anchor-fixed"><span class="ant-anchor-ink"></span>
|
||||||
<div class="ant-anchor-ink"><span class="ant-anchor-ink-ball"></span></div>
|
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,9 +117,8 @@ exports[`renders ./components/anchor/demo/onClick.vue correctly 1`] = `
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/anchor/demo/static.vue correctly 1`] = `
|
exports[`renders ./components/anchor/demo/static.vue correctly 1`] = `
|
||||||
<div class="ant-anchor-wrapper" style="max-height: 100vh;">
|
<div class="css-dev-only-do-not-override-1tii49m ant-anchor-wrapper" style="max-height: 100vh;">
|
||||||
<div class="ant-anchor ant-anchor-fixed">
|
<div class="ant-anchor ant-anchor-fixed"><span class="ant-anchor-ink"></span>
|
||||||
<div class="ant-anchor-ink"><span class="ant-anchor-ink-ball"></span></div>
|
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
|
@ -119,10 +139,10 @@ exports[`renders ./components/anchor/demo/static.vue correctly 1`] = `
|
||||||
|
|
||||||
exports[`renders ./components/anchor/demo/targetOffset.vue correctly 1`] = `
|
exports[`renders ./components/anchor/demo/targetOffset.vue correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div class="">
|
<!---->
|
||||||
<div class="ant-anchor-wrapper" style="max-height: 100vh;">
|
<div class="css-dev-only-do-not-override-1tii49m">
|
||||||
<div class="ant-anchor">
|
<div class="css-dev-only-do-not-override-1tii49m ant-anchor-wrapper" style="max-height: 100vh;">
|
||||||
<div class="ant-anchor-ink"><span class="ant-anchor-ink-ball"></span></div>
|
<div class="ant-anchor"><span class="ant-anchor-ink"></span>
|
||||||
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
<div class="ant-anchor-link"><a class="ant-anchor-link-title" href="#components-anchor-demo-basic" title="Basic demo">Basic demo</a>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { Ref, InjectionKey } from 'vue';
|
import type { Ref, InjectionKey, ComputedRef } from 'vue';
|
||||||
|
import type { AnchorDirection } from './Anchor';
|
||||||
import { computed, inject, provide } from 'vue';
|
import { computed, inject, provide } from 'vue';
|
||||||
|
|
||||||
export interface AnchorContext {
|
export interface AnchorContext {
|
||||||
|
@ -7,6 +8,7 @@ export interface AnchorContext {
|
||||||
activeLink: Ref<string>;
|
activeLink: Ref<string>;
|
||||||
scrollTo: (link: string) => void;
|
scrollTo: (link: string) => void;
|
||||||
handleClick: (e: Event, info: { title: any; href: string }) => void;
|
handleClick: (e: Event, info: { title: any; href: string }) => void;
|
||||||
|
direction: ComputedRef<AnchorDirection>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
@ -25,6 +27,7 @@ const useInjectAnchor = () => {
|
||||||
scrollTo: noop,
|
scrollTo: noop,
|
||||||
activeLink: computed(() => ''),
|
activeLink: computed(() => ''),
|
||||||
handleClick: noop,
|
handleClick: noop,
|
||||||
|
direction: computed(() => 'vertical'),
|
||||||
} as AnchorContext);
|
} as AnchorContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,23 @@ The simplest usage.
|
||||||
</docs>
|
</docs>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-anchor>
|
<a-anchor
|
||||||
<a-anchor-link href="#components-anchor-demo-basic" title="Basic demo" />
|
:items="[
|
||||||
<a-anchor-link href="#components-anchor-demo-static" title="Static demo" />
|
{
|
||||||
<a-anchor-link
|
key: 'part-1',
|
||||||
href="#components-anchor-demo-basic"
|
href: '#part-1',
|
||||||
title="Basic demo with Target"
|
title: 'Part 1',
|
||||||
target="_blank"
|
},
|
||||||
/>
|
{
|
||||||
<a-anchor-link href="#API" title="API">
|
key: 'part-2',
|
||||||
<a-anchor-link href="#Anchor-Props" title="Anchor Props" />
|
href: '#part-2',
|
||||||
<a-anchor-link href="#Link-Props" title="Link Props" />
|
title: 'Part 2',
|
||||||
</a-anchor-link>
|
},
|
||||||
</a-anchor>
|
{
|
||||||
|
key: 'part-3',
|
||||||
|
href: '#part-3',
|
||||||
|
title: 'Part 3',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
<docs>
|
||||||
|
---
|
||||||
|
order: 1
|
||||||
|
title:
|
||||||
|
zh-CN: 横向 Anchor。
|
||||||
|
en-US: Horizontally aligned anchors
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
横向 Anchor。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
Horizontally aligned anchors
|
||||||
|
|
||||||
|
</docs>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
{
|
||||||
|
padding: '20px';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<a-anchor
|
||||||
|
direction="horizontal"
|
||||||
|
:items="[
|
||||||
|
{
|
||||||
|
key: 'horizontally-part-1',
|
||||||
|
href: '#horizontally-part-1',
|
||||||
|
title: 'Part 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'horizontally-part-2',
|
||||||
|
href: '#horizontally-part-2',
|
||||||
|
title: 'Part 2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'horizontally-part-3',
|
||||||
|
href: '#horizontally-part-3',
|
||||||
|
title: 'Part 3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'horizontally-part-4',
|
||||||
|
href: '#horizontally-part-4',
|
||||||
|
title: 'Part 4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'horizontally-part-5',
|
||||||
|
href: '#horizontally-part-5',
|
||||||
|
title: 'Part 5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'horizontally-part-6',
|
||||||
|
href: '#horizontally-part-6',
|
||||||
|
title: 'Part 6',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<demo-sort>
|
<demo-sort>
|
||||||
<basic />
|
<basic />
|
||||||
|
<horizontal />
|
||||||
<static />
|
<static />
|
||||||
<on-click />
|
<on-click />
|
||||||
<customize-highlight />
|
<customize-highlight />
|
||||||
|
@ -16,6 +17,7 @@ import OnClick from './onClick.vue';
|
||||||
import CustomizeHighlight from './customizeHighlight.vue';
|
import CustomizeHighlight from './customizeHighlight.vue';
|
||||||
import TargetOffset from './targetOffset.vue';
|
import TargetOffset from './targetOffset.vue';
|
||||||
import OnChange from './onChange.vue';
|
import OnChange from './onChange.vue';
|
||||||
|
import Horizontal from './horizontal.vue';
|
||||||
import CN from '../index.zh-CN.md';
|
import CN from '../index.zh-CN.md';
|
||||||
import US from '../index.en-US.md';
|
import US from '../index.en-US.md';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
@ -29,6 +31,7 @@ export default defineComponent({
|
||||||
OnClick,
|
OnClick,
|
||||||
CustomizeHighlight,
|
CustomizeHighlight,
|
||||||
TargetOffset,
|
TargetOffset,
|
||||||
|
Horizontal,
|
||||||
OnChange,
|
OnChange,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
category: Components
|
category: Components
|
||||||
type: Other
|
type: Navigation
|
||||||
cols: 2
|
cols: 2
|
||||||
title: Anchor
|
title: Anchor
|
||||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
||||||
|
@ -29,7 +29,18 @@ For displaying anchor hyperlinks on page and jumping between them.
|
||||||
| targetOffset | Anchor scroll offset, default as `offsetTop`, [example](#components-anchor-demo-targetOffset) | number | `offsetTop` | 1.5.0 |
|
| targetOffset | Anchor scroll offset, default as `offsetTop`, [example](#components-anchor-demo-targetOffset) | number | `offsetTop` | 1.5.0 |
|
||||||
| wrapperClass | The class name of the container | string | - | |
|
| wrapperClass | The class name of the container | string | - | |
|
||||||
| wrapperStyle | The style of the container | object | - | |
|
| wrapperStyle | The style of the container | object | - | |
|
||||||
| items | Data configuration option content, support nesting through children | { href, title, target, children, key }\[] | - | 4.0 |
|
| items | Data configuration option content, support nesting through children | { key, href, title, target, children }\[] [see](#anchoritem) | - | 4.0 |
|
||||||
|
| direction | Set Anchor direction | `vertical` \| `horizontal` | `vertical` | 4.0 |
|
||||||
|
|
||||||
|
### AnchorItem
|
||||||
|
|
||||||
|
| Property | Description | Type | Default | Version |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| key | The unique identifier of the Anchor Link | string \| number | - | |
|
||||||
|
| href | The target of hyperlink | string | | |
|
||||||
|
| target | Specifies where to display the linked URL | string | | |
|
||||||
|
| title | The content of hyperlink | VueNode \| (item: AnchorItem) => VueNode | | |
|
||||||
|
| children | Nested Anchor Link, `Attention: This attribute does not support horizontal orientation` | [AnchorItem](#anchoritem)\[] | - | |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
category: Components
|
category: Components
|
||||||
subtitle: 锚点
|
subtitle: 锚点
|
||||||
cols: 2
|
cols: 2
|
||||||
type: 其他
|
type: 导航
|
||||||
title: Anchor
|
title: Anchor
|
||||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
|
||||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
|
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
|
||||||
|
@ -30,7 +30,18 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAA
|
||||||
| targetOffset | 锚点滚动偏移量,默认与 offsetTop 相同,[例子](#components-anchor-demo-targetOffset) | number | `offsetTop` | 1.5.0 |
|
| targetOffset | 锚点滚动偏移量,默认与 offsetTop 相同,[例子](#components-anchor-demo-targetOffset) | number | `offsetTop` | 1.5.0 |
|
||||||
| wrapperClass | 容器的类名 | string | - | |
|
| wrapperClass | 容器的类名 | string | - | |
|
||||||
| wrapperStyle | 容器样式 | object | - | |
|
| wrapperStyle | 容器样式 | object | - | |
|
||||||
| items | 数据化配置选项内容,支持通过 children 嵌套 | { href, title, target, children, key }\[] | - | 4.0 |
|
| items | 数据化配置选项内容,支持通过 children 嵌套 | { key, href, title, target, children }\[] [具体见](#anchoritem) | - | 4.0 |
|
||||||
|
| direction | 设置导航方向 | `vertical` \| `horizontal` | `vertical` | 4.0 |
|
||||||
|
|
||||||
|
### AnchorItem
|
||||||
|
|
||||||
|
| 成员 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| key | 唯一标志 | string \| number | - | |
|
||||||
|
| href | 锚点链接 | string | - | |
|
||||||
|
| target | 该属性指定在何处显示链接的资源 | string | - | |
|
||||||
|
| title | 文字内容 | VueNode \| (item: AnchorItem) => VueNode | - | |
|
||||||
|
| children | 嵌套的 Anchor Link,`注意:水平方向该属性不支持` | [AnchorItem](#anchoritem)\[] | - | |
|
||||||
|
|
||||||
### 事件
|
### 事件
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,15 @@ interface AnchorToken extends FullToken<'Anchor'> {
|
||||||
|
|
||||||
// ============================== Shared ==============================
|
// ============================== Shared ==============================
|
||||||
const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
|
const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
|
||||||
const { componentCls, holderOffsetBlock, motionDurationSlow, lineWidthBold, colorPrimary } =
|
const {
|
||||||
token;
|
componentCls,
|
||||||
|
holderOffsetBlock,
|
||||||
|
motionDurationSlow,
|
||||||
|
lineWidthBold,
|
||||||
|
colorPrimary,
|
||||||
|
lineType,
|
||||||
|
colorSplit,
|
||||||
|
} = token;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[`${componentCls}-wrapper`]: {
|
[`${componentCls}-wrapper`]: {
|
||||||
|
@ -34,40 +41,6 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
paddingInlineStart: lineWidthBold,
|
paddingInlineStart: lineWidthBold,
|
||||||
|
|
||||||
[`${componentCls}-ink`]: {
|
|
||||||
position: 'absolute',
|
|
||||||
insetBlockStart: 0,
|
|
||||||
insetInlineStart: 0,
|
|
||||||
height: '100%',
|
|
||||||
|
|
||||||
'&::before': {
|
|
||||||
position: 'relative',
|
|
||||||
display: 'block',
|
|
||||||
width: lineWidthBold,
|
|
||||||
height: '100%',
|
|
||||||
margin: '0 auto',
|
|
||||||
backgroundColor: token.colorSplit,
|
|
||||||
content: '" "',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
[`${componentCls}-ink-ball`]: {
|
|
||||||
position: 'absolute',
|
|
||||||
left: {
|
|
||||||
_skip_check_: true,
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
display: 'none',
|
|
||||||
transform: 'translateY(-50%)',
|
|
||||||
transition: `top ${motionDurationSlow} ease-in-out`,
|
|
||||||
width: lineWidthBold,
|
|
||||||
backgroundColor: colorPrimary,
|
|
||||||
|
|
||||||
[`&${componentCls}-ink-ball-visible`]: {
|
|
||||||
display: 'inline-block',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
[`${componentCls}-link`]: {
|
[`${componentCls}-link`]: {
|
||||||
paddingBlock: token.anchorPaddingBlock,
|
paddingBlock: token.anchorPaddingBlock,
|
||||||
paddingInline: `${token.anchorPaddingInline}px 0`,
|
paddingInline: `${token.anchorPaddingInline}px 0`,
|
||||||
|
@ -96,13 +69,94 @@ const genSharedAnchorStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
[`${componentCls}-fixed ${componentCls}-ink ${componentCls}-ink-ball`]: {
|
[`&:not(${componentCls}-wrapper-horizontal)`]: {
|
||||||
|
[componentCls]: {
|
||||||
|
'&::before': {
|
||||||
|
position: 'absolute',
|
||||||
|
left: {
|
||||||
|
_skip_check_: true,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
top: 0,
|
||||||
|
height: '100%',
|
||||||
|
borderInlineStart: `${lineWidthBold}px ${lineType} ${colorSplit}`,
|
||||||
|
content: '" "',
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-ink`]: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: {
|
||||||
|
_skip_check_: true,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
display: 'none',
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
transition: `top ${motionDurationSlow} ease-in-out`,
|
||||||
|
width: lineWidthBold,
|
||||||
|
backgroundColor: colorPrimary,
|
||||||
|
|
||||||
|
[`&${componentCls}-ink-visible`]: {
|
||||||
|
display: 'inline-block',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-fixed ${componentCls}-ink ${componentCls}-ink`]: {
|
||||||
display: 'none',
|
display: 'none',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const genSharedAnchorHorizontalStyle: GenerateStyle<AnchorToken> = (token): CSSObject => {
|
||||||
|
const { componentCls, motionDurationSlow, lineWidthBold, colorPrimary } = token;
|
||||||
|
|
||||||
|
return {
|
||||||
|
[`${componentCls}-wrapper-horizontal`]: {
|
||||||
|
position: 'relative',
|
||||||
|
|
||||||
|
'&::before': {
|
||||||
|
position: 'absolute',
|
||||||
|
left: {
|
||||||
|
_skip_check_: true,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
_skip_check_: true,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
bottom: 0,
|
||||||
|
borderBottom: `1px ${token.lineType} ${token.colorSplit}`,
|
||||||
|
content: '" "',
|
||||||
|
},
|
||||||
|
|
||||||
|
[componentCls]: {
|
||||||
|
overflowX: 'scroll',
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
scrollbarWidth: 'none' /* Firefox */,
|
||||||
|
|
||||||
|
'&::-webkit-scrollbar': {
|
||||||
|
display: 'none' /* Safari and Chrome */,
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-link:first-of-type`]: {
|
||||||
|
paddingInline: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-ink`]: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
transition: `left ${motionDurationSlow} ease-in-out, width ${motionDurationSlow} ease-in-out`,
|
||||||
|
height: lineWidthBold,
|
||||||
|
backgroundColor: colorPrimary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// ============================== Export ==============================
|
// ============================== Export ==============================
|
||||||
export default genComponentStyleHook('Anchor', token => {
|
export default genComponentStyleHook('Anchor', token => {
|
||||||
const { fontSize, fontSizeLG, padding, paddingXXS } = token;
|
const { fontSize, fontSizeLG, padding, paddingXXS } = token;
|
||||||
|
@ -115,5 +169,5 @@ export default genComponentStyleHook('Anchor', token => {
|
||||||
anchorTitleBlock: (fontSize / 14) * 3,
|
anchorTitleBlock: (fontSize / 14) * 3,
|
||||||
anchorBallSize: fontSizeLG / 2,
|
anchorBallSize: fontSizeLG / 2,
|
||||||
});
|
});
|
||||||
return [genSharedAnchorStyle(anchorToken)];
|
return [genSharedAnchorStyle(anchorToken), genSharedAnchorHorizontalStyle(anchorToken)];
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue