Commit 8cf939c0 authored by XieZhiXiong's avatar XieZhiXiong

feat: 添加 AnchorPage 带锚点头部页面布局组件

parent e9600160
/*
* @Author: XieZhiXiong
* @Date: 2021-05-11 09:44:16
* @LastEditors: XieZhiXiong
* @LastEditTime: 2021-05-11 10:14:07
* @Description: 获取 DOM 节点的位置 或是 大小 hook
*/
import { useState, useCallback } from 'react';
interface RectData {
/**
* 元素高度
*/
height: number,
/**
* 元素宽度
*/
width: number,
/**
* 元素顶部距离视口的距离
*/
top: number,
/**
* 元素右侧距离视口的距离
*/
right: number,
/**
* 元素底部距离视口的距离
*/
bottom: number,
/**
* 元素左侧距离视口的距离
*/
left: number,
/**
* 元素距离左上角坐标 (0, 0)的 x 坐标值
*/
x: number,
/**
* 元素距离左上角坐标 (0, 0)的 y 坐标值
*/
y: number,
}
const useClientRect = (): [RectData, any] => {
const [rect, setRect] = useState({
height: 0,
width: 0,
top: 0,
right: 0,
bottom: 0,
left: 0,
x: 0,
y: 0,
});
const ref = useCallback(node => {
if (node !== null) {
setRect(node.getBoundingClientRect());
}
}, []);
return [rect, ref];
}
export default useClientRect;
@import '~antd/es/style/themes/default.less'; @import '~antd/es/style/themes/default.less';
.anchor-page-header { .anchor-page {
display: flex; &-header {
background: #FFFFFF; background: #FFFFFF;
&-main {
padding: 0 16px;
display: flex;
}
&-left { &-left {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
...@@ -16,7 +21,7 @@ ...@@ -16,7 +21,7 @@
} }
&-heading { &-heading {
padding: 14px 0; padding: 14px 0 9px 0;
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -41,4 +46,44 @@ ...@@ -41,4 +46,44 @@
color: @primary-color; color: @primary-color;
} }
} }
&-anchors {
display: flex;
align-items: center;
}
:global {
.ant-anchor {
&-link {
padding: 0 16px;
font-size: 14px;
font-weight: 400;
color: @text-color;
&-title {
padding: 16px 0;
border-bottom: 2px solid transparent;
}
&-active,
&:hover {
font-weight: 500;
color: @text-color;
.ant-anchor-link-title {
border-bottom: 2px solid @primary-color;
}
}
}
&-ink {
display: none;
}
}
}
}
&-content {
padding: 16px;
}
} }
\ No newline at end of file
...@@ -2,13 +2,14 @@ ...@@ -2,13 +2,14 @@
* @Author: XieZhiXiong * @Author: XieZhiXiong
* @Date: 2021-05-10 11:36:58 * @Date: 2021-05-10 11:36:58
* @LastEditors: XieZhiXiong * @LastEditors: XieZhiXiong
* @LastEditTime: 2021-05-10 15:05:20 * @LastEditTime: 2021-05-11 10:16:12
* @Description: 页面公用锚点头部 * @Description: 页面公用锚点头部
*/ */
import React from 'react'; import React, { useState } from 'react';
import { Anchor, Button } from 'antd'; import { Anchor } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons'; import { ArrowLeftOutlined } from '@ant-design/icons';
import { history } from 'umi'; import { history } from 'umi';
import useClientRect from '@/hooks/useClientRect';
import styles from './index.less'; import styles from './index.less';
export interface AnchorsItem { export interface AnchorsItem {
...@@ -35,6 +36,12 @@ interface IProps { ...@@ -35,6 +36,12 @@ interface IProps {
* 锚点数据 * 锚点数据
*/ */
anchors: AnchorsItem[], anchors: AnchorsItem[],
/**
* 自定义样式
*/
customStyle?: React.CSSProperties,
children?: React.ReactNode,
} }
const AnchorPageHeader: React.FC<IProps> = (props: IProps) => { const AnchorPageHeader: React.FC<IProps> = (props: IProps) => {
...@@ -42,14 +49,48 @@ const AnchorPageHeader: React.FC<IProps> = (props: IProps) => { ...@@ -42,14 +49,48 @@ const AnchorPageHeader: React.FC<IProps> = (props: IProps) => {
title, title,
extra, extra,
anchors, anchors,
customStyle,
children,
} = props; } = props;
const firstKey = anchors.length ? `#${anchors[0].key}` : '';
const [current, setCurrent] = useState(firstKey);
const [rect, measuredRef] = useClientRect();
const handleBack = () => { const handleBack = () => {
history.goBack(); history.goBack();
}; };
const handleAnchorChange = (currentActiveLink: string) => {
if (currentActiveLink) {
setCurrent('');
return;
}
if (!currentActiveLink) {
setCurrent(firstKey);
}
};
const handleAnchorClick = (e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
};
return ( return (
<div className={styles['anchor-page-header']}> <div
className={styles['anchor-page']}
style={customStyle}
>
<div
className={styles['anchor-page-header']}
style={customStyle}
ref={measuredRef}
>
<Anchor
showInkInFixed={false}
targetOffset={rect.height}
onChange={handleAnchorChange}
onClick={handleAnchorClick}
>
<div className={styles['anchor-page-header-main']}>
<div className={styles['anchor-page-header-left']}> <div className={styles['anchor-page-header-left']}>
<div className={styles['anchor-page-header-heading']}> <div className={styles['anchor-page-header-heading']}>
<ArrowLeftOutlined <ArrowLeftOutlined
...@@ -61,7 +102,16 @@ const AnchorPageHeader: React.FC<IProps> = (props: IProps) => { ...@@ -61,7 +102,16 @@ const AnchorPageHeader: React.FC<IProps> = (props: IProps) => {
</span> </span>
</div> </div>
<div className={styles['anchor-page-header-content']}> <div className={styles['anchor-page-header-content']}>
123 <div className={styles['anchor-page-header-anchors']}>
{anchors.map((item, index) => (
<Anchor.Link
className={current && index === 0 ? 'ant-anchor-link-active' : null}
key={item.key}
href={`#${item.key}`}
title={item.name}
/>
))}
</div>
</div> </div>
</div> </div>
{extra ? ( {extra ? (
...@@ -70,11 +120,19 @@ const AnchorPageHeader: React.FC<IProps> = (props: IProps) => { ...@@ -70,11 +120,19 @@ const AnchorPageHeader: React.FC<IProps> = (props: IProps) => {
</div> </div>
) : null} ) : null}
</div> </div>
</Anchor>
</div>
<div className={styles['anchor-page-content']}>
{children}
</div>
</div>
); );
}; };
AnchorPageHeader.defaultProps = { AnchorPageHeader.defaultProps = {
extra: null, extra: null,
customStyle: {},
children: null,
}; };
export default AnchorPageHeader; export default AnchorPageHeader;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment