diff --git a/components/anchor/Anchor.tsx b/components/anchor/Anchor.tsx index 167ab5f38..484760569 100644 --- a/components/anchor/Anchor.tsx +++ b/components/anchor/Anchor.tsx @@ -1,6 +1,5 @@ import type { CSSProperties, ExtractPropTypes, PropType } from 'vue'; import { - watch, defineComponent, nextTick, onBeforeUnmount, @@ -19,18 +18,11 @@ import getScroll from '../_util/getScroll'; import useConfigInject from '../config-provider/hooks/useConfigInject'; import useProvideAnchor from './context'; import useStyle from './style'; -import type { AnchorLinkProps } from './AnchorLink'; +import type { AnchorLinkItemProps } from './AnchorLink'; import AnchorLink from './AnchorLink'; -import type { Key } from '../_util/type'; import PropTypes from '../_util/vue-types'; import devWarning from '../vc-util/devWarning'; - -export interface AnchorLinkItemProps extends AnchorLinkProps { - key: Key; - class?: String; - style?: CSSProperties; - children?: AnchorLinkItemProps[]; -} +import { arrayType } from '../_util/type'; export type AnchorDirection = 'vertical' | 'horizontal'; @@ -76,10 +68,7 @@ export const anchorProps = () => ({ wrapperStyle: { type: Object as PropType, default: undefined as CSSProperties }, getCurrentAnchor: Function as PropType<(activeLink: string) => string>, targetOffset: Number, - items: { - type: Array as PropType, - default: undefined as AnchorLinkItemProps[], - }, + items: arrayType(), direction: PropTypes.oneOf(['vertical', 'horizontal'] as AnchorDirection[]).def('vertical'), onChange: Function as PropType<(currentActiveLink: string) => void>, onClick: Function as PropType<(e: MouseEvent, link: { title: any; href: string }) => void>, @@ -105,7 +94,7 @@ export default defineComponent({ if (process.env.NODE_ENV !== 'production') { devWarning( - typeof slots.default !== 'function', + props.items && typeof slots.default !== 'function', 'Anchor', '`Anchor children` is deprecated. Please use `items` instead.', ); @@ -274,17 +263,25 @@ export default defineComponent({ updateInk(); }); - watch([anchorDirection, getCurrentAnchor, state.links, activeLink], () => { - updateInk(); - }); - const createNestedLink = (options?: AnchorLinkItemProps[]) => Array.isArray(options) - ? options.map(item => ( - - {anchorDirection.value === 'vertical' ? createNestedLink(item.children) : null} - - )) + ? options.map(option => { + const { children, key, href, target, class: cls, style, title } = option; + return ( + + {anchorDirection.value === 'vertical' ? createNestedLink(children) : null} + + ); + }) : null; const [wrapSSR, hashId] = useStyle(prefixCls); diff --git a/components/anchor/AnchorLink.tsx b/components/anchor/AnchorLink.tsx index 798556887..312471ee0 100644 --- a/components/anchor/AnchorLink.tsx +++ b/components/anchor/AnchorLink.tsx @@ -1,26 +1,40 @@ import type { ExtractPropTypes } from 'vue'; import { defineComponent, nextTick, onBeforeUnmount, onMounted, watch } from 'vue'; -import PropTypes from '../_util/vue-types'; -import { getPropsSlot, initDefaultProps } from '../_util/props-util'; +import { initDefaultProps } from '../_util/props-util'; import classNames from '../_util/classNames'; import useConfigInject from '../config-provider/hooks/useConfigInject'; import { useInjectAnchor } from './context'; +import type { Key, VueNode } from '../_util/type'; +import { objectType, anyType } from '../_util/type'; +import type { CSSProperties } from '../_util/cssinjs/hooks/useStyleRegister'; export const anchorLinkProps = () => ({ prefixCls: String, href: String, - title: PropTypes.any, + title: anyType VueNode)>(), target: String, + /* private use */ + customTitleProps: objectType(), }); +export interface AnchorLinkItemProps { + key: Key; + class?: string; + style?: CSSProperties; + href?: string; + target?: string; + children?: AnchorLinkItemProps[]; + title?: VueNode | ((item: AnchorLinkItemProps) => VueNode); +} export type AnchorLinkProps = Partial>>; export default defineComponent({ compatConfig: { MODE: 3 }, name: 'AAnchorLink', + inheritAttrs: false, props: initDefaultProps(anchorLinkProps(), { href: '#' }), - slots: ['title'], - setup(props, { slots }) { + slots: ['title', 'customTitle'], + setup(props, { slots, attrs }) { let mergedTitle = null; const { handleClick: contextHandleClick, @@ -56,27 +70,30 @@ export default defineComponent({ }); return () => { - const { href, target } = props; + const { href, target, title = slots.title, customTitleProps = {} } = props; const pre = prefixCls.value; - const title = getPropsSlot(slots, props, 'title'); - mergedTitle = title; + mergedTitle = typeof title === 'function' ? title(customTitleProps) : title; const active = activeLink.value === href; - const wrapperClassName = classNames(`${pre}-link`, { - [`${pre}-link-active`]: active, - }); + const wrapperClassName = classNames( + `${pre}-link`, + { + [`${pre}-link-active`]: active, + }, + attrs.class, + ); const titleClassName = classNames(`${pre}-link-title`, { [`${pre}-link-title-active`]: active, }); return ( -
+ diff --git a/components/anchor/demo/basic.vue b/components/anchor/demo/basic.vue index a21bf1196..985427d34 100644 --- a/components/anchor/demo/basic.vue +++ b/components/anchor/demo/basic.vue @@ -21,7 +21,7 @@ The simplest usage. { key: 'part-1', href: '#part-1', - title: 'Part 1', + title: () => h('span', { style: 'color: red' }, 'Part 1'), }, { key: 'part-2', @@ -36,3 +36,19 @@ The simplest usage. ]" /> + + diff --git a/components/anchor/demo/customizeHighlight.vue b/components/anchor/demo/customizeHighlight.vue index ca7ee0843..eea5c7543 100644 --- a/components/anchor/demo/customizeHighlight.vue +++ b/components/anchor/demo/customizeHighlight.vue @@ -16,14 +16,39 @@ Customize the anchor highlight.