- antd 3.x版本的Affix在抽屉组件中不生效
- 可以利用sticky来做
- 在目标元素中声明:position: 'sticky', top: '0'
- 目标元素的父元素上不能有:visible: hidden属性
设置抽屉下.ant-tabs属性为:overflow: visible !important;
- 利用js原生代码结合React.useLayoutEffect, React.useRef来做
- 通过React.useRef获取到真实dom元素
const paneRef = React.useRef<{
question: HTMLDivElement;
service: HTMLDivElement;
}>({
question: null,
service: null,
});
<div
ref={(ref) => {
paneRef.current.question = ref;
}}
>
<Alert
type="info"
message="此设置为质检、培训能力通用,请慎重修改哦"
showIcon
/>
</div>
- 找到显示滚动条的元素
function findParentNode(className: string, sourceNode: HTMLElement) {
let parent = sourceNode.parentElement;
while (parent !== document.body) {
if (parent.classList.contains(className)) {
return parent;
} else {
parent = parent.parentElement;
}
}
return null;
}
- 利用React.useLayoutEffect为显示滚动条元素绑定scroll事件
React.useLayoutEffect(() => {
let listenerNode;
if (paneRef.current[TabType[tabType]]) {
listenerNode = findParentNode(
'ant-drawer-wrapper-body',
paneRef.current[TabType[tabType]]
);
listenerNode.addEventListener('scroll', throttle(handleAffix, TabType[tabType], 20));
}
return () => {
listenerNode.addEventListener('scroll', throttle(handleAffix, TabType[tabType], 20));
}
}, [tabType]);
- 利用原生js实现目标元素affix效果
const handleAffix = (type) => {
const parent = paneRef.current[type];
if (parent.getBoundingClientRect().top < 0) {
const child = parent.children[0];
child.classList.add('affix');
} else {
const child = parent.children[0];
child.classList.remove('affix');
}
};
- 加一层函数的节流, 大功告成
const throttle = (fn, type, delay) => {
let prev = Date.now();
return function () {
const context = this;
const now = Date.now();
if (now - prev >= delay) {
fn.apply(context, [type]);
prev = Date.now();
}
};
};
- 全部代码
import * as React from 'react';
import { Tabs, Alert } from 'antd';
import TreeEditor from './TreeEditor';
import { ServiceType } from '../../services/types';
const { TabPane } = Tabs;
enum TabType {
question,
service,
}
function findParentNode(className: string, sourceNode: HTMLElement) {
let parent = sourceNode.parentElement;
while (parent !== document.body) {
if (parent.classList.contains(className)) {
return parent;
} else {
parent = parent.parentElement;
}
}
return null;
}
export interface ServiceRulesProps {
onChange?: () => void;
activeKey?: ServiceType;
}
export const ServiceRules: React.FC<ServiceRulesProps> = (props) => {
const { onChange, activeKey } = props;
const paneRef = React.useRef<{
question: HTMLDivElement;
service: HTMLDivElement;
}>({
question: null,
service: null,
});
const handleChange = () => {
onChange && onChange();
};
const [tabType, setTabType] = React.useState(TabType.question);
React.useLayoutEffect(() => {
let listenerNode;
if (paneRef.current[TabType[tabType]]) {
listenerNode = findParentNode(
'ant-drawer-wrapper-body',
paneRef.current[TabType[tabType]]
);
listenerNode.addEventListener('scroll', throttle(handleAffix, TabType[tabType], 20));
}
return () => {
listenerNode.addEventListener('scroll', throttle(handleAffix, TabType[tabType], 20));
}
}, [tabType]);
const handleAffix = (type) => {
const parent = paneRef.current[type];
if (parent.getBoundingClientRect().top < 0) {
const child = parent.children[0];
child.classList.add('affix');
} else {
const child = parent.children[0];
child.classList.remove('affix');
}
};
const throttle = (fn, type, delay) => {
let prev = Date.now();
return function () {
const context = this;
const now = Date.now();
if (now - prev >= delay) {
fn.apply(context, [type]);
prev = Date.now();
}
};
};
const handleTabChange = (key) => {
setTabType(key);
};
return (
<Tabs
defaultActiveKey={String(activeKey)}
tabBarStyle={{ padding: '5px 24px 0 24px', margin: 0 }}
onChange={handleTabChange}
>
<TabPane className="tab-container" tab="服务问题" key="0">
<div
ref={(ref) => {
paneRef.current.question = ref;
}}
>
<Alert
type="info"
message="此设置为质检、培训能力通用,请慎重修改哦"
showIcon
/>
</div>
<TreeEditor
onChange={handleChange}
serviceType={ServiceType.disadvantages}
style={{ marginTop: 18 }}
/>
</TabPane>
<TabPane className="tab-container" tab="服务亮点" key="1">
<div
ref={(ref) => {
paneRef.current.service = ref;
}}
>
<Alert
type="info"
message="此设置为质检、培训能力通用,请慎重修改哦"
showIcon
/>
</div>
<TreeEditor
onChange={handleChange}
serviceType={ServiceType.advantages}
style={{ marginTop: 18 }}
/>
</TabPane>
</Tabs>
);
};
ServiceRules.defaultProps = {
activeKey: ServiceType.disadvantages,
};