refactor: backtop
parent
6c735fee67
commit
e64a19a05a
|
@ -42,3 +42,7 @@ export const withInstall = <T>(comp: T) => {
|
|||
};
|
||||
|
||||
export type MaybeRef<T> = T | Ref<T>;
|
||||
|
||||
export function eventType<T>() {
|
||||
return { type: [Function, Array] as PropType<T | T[]> };
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ You can customize the style of the button, just note the size limit: no more tha
|
|||
|
||||
<template>
|
||||
<div id="components-back-top-demo-custom">
|
||||
<a-back-top>
|
||||
<a-back-top @click="handleClick">
|
||||
<div class="ant-back-top-inner">UP</div>
|
||||
</a-back-top>
|
||||
Scroll down to see the bottom-right
|
||||
|
@ -25,10 +25,15 @@ You can customize the style of the button, just note the size limit: no more tha
|
|||
button.
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
const handleClick = () => {
|
||||
console.log('click');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#components-back-top-demo-custom .ant-back-top {
|
||||
bottom: 100px;
|
||||
:deep(#components-back-top-demo-custom) .ant-back-top {
|
||||
inset-block-end: 100px;
|
||||
}
|
||||
#components-back-top-demo-custom .ant-back-top-inner {
|
||||
height: 40px;
|
||||
|
|
|
@ -11,21 +11,21 @@ import {
|
|||
onDeactivated,
|
||||
} from 'vue';
|
||||
import VerticalAlignTopOutlined from '@ant-design/icons-vue/VerticalAlignTopOutlined';
|
||||
import addEventListener from '../vc-util/Dom/addEventListener';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import { getTransitionProps, Transition } from '../_util/transition';
|
||||
import scrollTo from '../_util/scrollTo';
|
||||
import { withInstall } from '../_util/type';
|
||||
import { withInstall, eventType } from '../_util/type';
|
||||
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
import type { MouseEventHandler } from '../_util/EventInterface';
|
||||
import useStyle from './style';
|
||||
|
||||
export const backTopProps = () => ({
|
||||
visibilityHeight: { type: Number, default: 400 },
|
||||
duration: { type: Number, default: 450 },
|
||||
target: Function as PropType<() => HTMLElement | Window | Document>,
|
||||
prefixCls: String,
|
||||
onClick: Function as PropType<MouseEventHandler>,
|
||||
onClick: eventType<MouseEventHandler>(),
|
||||
// visible: { type: Boolean, default: undefined }, // Only for test. Don't use it.
|
||||
});
|
||||
|
||||
|
@ -39,6 +39,7 @@ const BackTop = defineComponent({
|
|||
// emits: ['click'],
|
||||
setup(props, { slots, attrs, emit }) {
|
||||
const { prefixCls, direction } = useConfigInject('back-top', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const domRef = ref();
|
||||
const state = reactive({
|
||||
visible: false,
|
||||
|
@ -60,26 +61,23 @@ const BackTop = defineComponent({
|
|||
const handleScroll = throttleByAnimationFrame((e: Event | { target: any }) => {
|
||||
const { visibilityHeight } = props;
|
||||
const scrollTop = getScroll(e.target, true);
|
||||
state.visible = scrollTop > visibilityHeight;
|
||||
state.visible = scrollTop >= visibilityHeight;
|
||||
});
|
||||
|
||||
const bindScrollEvent = () => {
|
||||
const { target } = props;
|
||||
const getTarget = target || getDefaultTarget;
|
||||
const container = getTarget();
|
||||
state.scrollEvent = addEventListener(container, 'scroll', (e: Event) => {
|
||||
handleScroll(e);
|
||||
});
|
||||
handleScroll({
|
||||
target: container,
|
||||
});
|
||||
handleScroll({ target: container });
|
||||
container?.addEventListener('scroll', handleScroll);
|
||||
};
|
||||
|
||||
const scrollRemove = () => {
|
||||
if (state.scrollEvent) {
|
||||
state.scrollEvent.remove();
|
||||
}
|
||||
(handleScroll as any).cancel();
|
||||
const { target } = props;
|
||||
const getTarget = target || getDefaultTarget;
|
||||
const container = getTarget();
|
||||
handleScroll.cancel();
|
||||
container?.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
|
||||
watch(
|
||||
|
@ -124,6 +122,7 @@ const BackTop = defineComponent({
|
|||
...attrs,
|
||||
onClick: scrollToTop,
|
||||
class: {
|
||||
[hashId.value]: true,
|
||||
[`${prefixCls.value}`]: true,
|
||||
[`${attrs.class}`]: attrs.class,
|
||||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
|
@ -131,12 +130,12 @@ const BackTop = defineComponent({
|
|||
};
|
||||
|
||||
const transitionProps = getTransitionProps('fade');
|
||||
return (
|
||||
return wrapSSR(
|
||||
<Transition {...transitionProps}>
|
||||
<div v-show={state.visible} {...divProps} ref={domRef}>
|
||||
{slots.default?.() || defaultElement}
|
||||
</div>
|
||||
</Transition>
|
||||
</Transition>,
|
||||
);
|
||||
};
|
||||
},
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@backtop-prefix-cls: ~'@{ant-prefix}-back-top';
|
||||
|
||||
.@{backtop-prefix-cls} {
|
||||
.reset-component();
|
||||
|
||||
position: fixed;
|
||||
right: 100px;
|
||||
bottom: 50px;
|
||||
z-index: @zindex-back-top;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-rtl {
|
||||
right: auto;
|
||||
left: 100px;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&-content {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
overflow: hidden;
|
||||
color: @back-top-color;
|
||||
text-align: center;
|
||||
background-color: @back-top-bg;
|
||||
border-radius: 20px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: @back-top-hover-bg;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
&-icon {
|
||||
font-size: 24px;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@import './responsive';
|
|
@ -0,0 +1,118 @@
|
|||
import type { CSSObject } from '../../_util/cssinjs';
|
||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||
import { resetComponent } from '../../_style';
|
||||
|
||||
/** Component only token. Which will handle additional calculation of alias token */
|
||||
export interface ComponentToken {
|
||||
zIndexPopup: number;
|
||||
}
|
||||
|
||||
type BackTopToken = FullToken<'BackTop'> & {
|
||||
backTopBackground: string;
|
||||
backTopColor: string;
|
||||
backTopHoverBackground: string;
|
||||
backTopFontSize: number;
|
||||
backTopSize: number;
|
||||
|
||||
// Position
|
||||
backTopBlockEnd: number;
|
||||
backTopInlineEnd: number;
|
||||
backTopInlineEndMD: number;
|
||||
backTopInlineEndXS: number;
|
||||
};
|
||||
|
||||
// ============================== Shared ==============================
|
||||
const genSharedBackTopStyle: GenerateStyle<BackTopToken, CSSObject> = (token): CSSObject => {
|
||||
const { componentCls, backTopFontSize, backTopSize, zIndexPopup } = token;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
|
||||
position: 'fixed',
|
||||
insetInlineEnd: token.backTopInlineEnd,
|
||||
insetBlockEnd: token.backTopBlockEnd,
|
||||
zIndex: zIndexPopup,
|
||||
width: 40,
|
||||
height: 40,
|
||||
cursor: 'pointer',
|
||||
|
||||
'&:empty': {
|
||||
display: 'none',
|
||||
},
|
||||
|
||||
[`${componentCls}-content`]: {
|
||||
width: backTopSize,
|
||||
height: backTopSize,
|
||||
overflow: 'hidden',
|
||||
color: token.backTopColor,
|
||||
textAlign: 'center',
|
||||
backgroundColor: token.backTopBackground,
|
||||
borderRadius: backTopSize,
|
||||
transition: `all ${token.motionDurationMid}`,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: token.backTopHoverBackground,
|
||||
transition: `all ${token.motionDurationMid}`,
|
||||
},
|
||||
},
|
||||
|
||||
// change to .backtop .backtop-icon
|
||||
[`${componentCls}-icon`]: {
|
||||
fontSize: backTopFontSize,
|
||||
lineHeight: `${backTopSize}px`,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const genMediaBackTopStyle: GenerateStyle<BackTopToken> = (token): CSSObject => {
|
||||
const { componentCls } = token;
|
||||
|
||||
return {
|
||||
[`@media (max-width: ${token.screenMD}px)`]: {
|
||||
[componentCls]: {
|
||||
insetInlineEnd: token.backTopInlineEndMD,
|
||||
},
|
||||
},
|
||||
|
||||
[`@media (max-width: ${token.screenXS}px)`]: {
|
||||
[componentCls]: {
|
||||
insetInlineEnd: token.backTopInlineEndXS,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genComponentStyleHook<'BackTop'>(
|
||||
'BackTop',
|
||||
|
||||
token => {
|
||||
const {
|
||||
fontSizeHeading3,
|
||||
colorTextDescription,
|
||||
colorTextLightSolid,
|
||||
colorText,
|
||||
controlHeightLG,
|
||||
} = token;
|
||||
|
||||
const backTopToken = mergeToken<BackTopToken>(token, {
|
||||
backTopBackground: colorTextDescription,
|
||||
backTopColor: colorTextLightSolid,
|
||||
backTopHoverBackground: colorText,
|
||||
backTopFontSize: fontSizeHeading3,
|
||||
backTopSize: controlHeightLG,
|
||||
|
||||
backTopBlockEnd: controlHeightLG * 1.25,
|
||||
backTopInlineEnd: controlHeightLG * 2.5,
|
||||
backTopInlineEndMD: controlHeightLG * 1.5,
|
||||
backTopInlineEndXS: controlHeightLG * 0.5,
|
||||
});
|
||||
return [genSharedBackTopStyle(backTopToken), genMediaBackTopStyle(backTopToken)];
|
||||
},
|
||||
token => ({
|
||||
zIndexPopup: token.zIndexBase + 10,
|
||||
}),
|
||||
);
|
|
@ -1,2 +0,0 @@
|
|||
import '../../style/index.less';
|
||||
import './index.less';
|
|
@ -1,21 +0,0 @@
|
|||
@media screen and (max-width: @screen-md) {
|
||||
.@{backtop-prefix-cls} {
|
||||
right: 60px;
|
||||
|
||||
&-rtl {
|
||||
right: auto;
|
||||
left: 60px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: @screen-xs) {
|
||||
.@{backtop-prefix-cls} {
|
||||
right: 20px;
|
||||
|
||||
&-rtl {
|
||||
right: auto;
|
||||
left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ import './switch/style';
|
|||
import './auto-complete/style';
|
||||
// import './affix/style';
|
||||
import './cascader/style';
|
||||
import './back-top/style';
|
||||
// import './back-top/style';
|
||||
import './modal/style';
|
||||
// import './alert/style';
|
||||
import './time-picker/style';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { ComponentToken as AlertComponentToken } from '../../alert/style';
|
||||
import type { ComponentToken as AnchorComponentToken } from '../../anchor/style';
|
||||
import type { ComponentToken as AvatarComponentToken } from '../../avatar/style';
|
||||
// import type { ComponentToken as BackTopComponentToken } from '../../back-top/style';
|
||||
import type { ComponentToken as BackTopComponentToken } from '../../back-top/style';
|
||||
// import type { ComponentToken as ButtonComponentToken } from '../../button/style';
|
||||
// import type { ComponentToken as FloatButtonComponentToken } from '../../float-button/style';
|
||||
// import type { ComponentToken as CalendarComponentToken } from '../../calendar/style';
|
||||
|
@ -55,32 +55,32 @@ export interface ComponentTokenMap {
|
|||
Alert?: AlertComponentToken;
|
||||
Anchor?: AnchorComponentToken;
|
||||
Avatar?: AvatarComponentToken;
|
||||
// BackTop?: BackTopComponentToken;
|
||||
// Badge?: {};
|
||||
BackTop?: BackTopComponentToken;
|
||||
Badge?: {};
|
||||
// Button?: ButtonComponentToken;
|
||||
// Breadcrumb?: {};
|
||||
Breadcrumb?: {};
|
||||
// Card?: CardComponentToken;
|
||||
// Carousel?: CarouselComponentToken;
|
||||
// Cascader?: CascaderComponentToken;
|
||||
// Checkbox?: CheckboxComponentToken;
|
||||
// Collapse?: CollapseComponentToken;
|
||||
// DatePicker?: DatePickerComponentToken;
|
||||
// Descriptions?: {};
|
||||
Descriptions?: {};
|
||||
// Divider?: DividerComponentToken;
|
||||
// Drawer?: DrawerComponentToken;
|
||||
// Dropdown?: DropdownComponentToken;
|
||||
// Empty?: EmptyComponentToken;
|
||||
// FloatButton?: FloatButtonComponentToken;
|
||||
// Form?: {};
|
||||
// Grid?: {};
|
||||
Form?: {};
|
||||
Grid?: {};
|
||||
// Image?: ImageComponentToken;
|
||||
// Input?: {};
|
||||
Input?: {};
|
||||
// InputNumber?: InputNumberComponentToken;
|
||||
// Layout?: LayoutComponentToken;
|
||||
// List?: ListComponentToken;
|
||||
// Mentions?: MentionsComponentToken;
|
||||
// Notification?: NotificationComponentToken;
|
||||
// Pagination?: {};
|
||||
Pagination?: {};
|
||||
// Popover?: PopoverComponentToken;
|
||||
// Popconfirm?: PopconfirmComponentToken;
|
||||
// Rate?: RateComponentToken;
|
||||
|
@ -91,11 +91,11 @@ export interface ComponentTokenMap {
|
|||
// Skeleton?: SkeletonComponentToken;
|
||||
// Slider?: SliderComponentToken;
|
||||
// Spin?: SpinComponentToken;
|
||||
// Statistic?: {};
|
||||
// Switch?: {};
|
||||
Statistic?: {};
|
||||
Switch?: {};
|
||||
// Tag?: TagComponentToken;
|
||||
// Tree?: {};
|
||||
// TreeSelect?: {};
|
||||
Tree?: {};
|
||||
TreeSelect?: {};
|
||||
// Typography?: TypographyComponentToken;
|
||||
// Timeline?: TimelineComponentToken;
|
||||
// Transfer?: TransferComponentToken;
|
||||
|
|
Loading…
Reference in New Issue