refactor: affix by ts

This commit is contained in:
tanjinzhou 2020-10-12 15:45:52 +08:00
parent f48ccdac01
commit 2185458744
3 changed files with 58 additions and 30 deletions

View File

@ -1,4 +1,4 @@
import { inject } from 'vue';
import { App, CSSProperties, defineComponent, inject } from 'vue';
import PropTypes from '../_util/vue-types';
import classNames from '../_util/classNames';
import omit from 'omit.js';
@ -18,6 +18,17 @@ import {
function getDefaultTarget() {
return typeof window !== 'undefined' ? window : null;
}
enum AffixStatus {
None,
Prepare,
}
export interface AffixState {
affixStyle?: CSSProperties;
placeholderStyle?: CSSProperties;
status: AffixStatus;
lastAffix: boolean;
prevTarget: Window | HTMLElement | null;
}
// Affix
const AffixProps = {
@ -36,11 +47,7 @@ const AffixProps = {
onChange: PropTypes.func,
onTestUpdatePosition: PropTypes.func,
};
const AffixStatus = {
None: 'none',
Prepare: 'Prepare',
};
const Affix = {
const Affix = defineComponent({
name: 'AAffix',
props: AffixProps,
mixins: [BaseMixin],
@ -49,6 +56,7 @@ const Affix = {
configProvider: inject('configProvider', defaultConfigProvider),
};
},
emits: ['change', 'testUpdatePosition'],
data() {
return {
affixStyle: undefined,
@ -56,6 +64,7 @@ const Affix = {
status: AffixStatus.None,
lastAffix: false,
prevTarget: null,
timeout: null,
};
},
beforeMount() {
@ -103,9 +112,9 @@ const Affix = {
beforeUnmount() {
clearTimeout(this.timeout);
removeObserveTarget(this);
this.updatePosition.cancel();
(this.updatePosition as any).cancel();
// https://github.com/ant-design/ant-design/issues/22683
this.lazyUpdatePosition.cancel();
(this.lazyUpdatePosition as any).cancel();
},
methods: {
getOffsetTop() {
@ -152,9 +161,9 @@ const Affix = {
const newState = {
status: AffixStatus.None,
};
} as AffixState;
const targetRect = getTargetRect(targetNode);
const placeholderReact = getTargetRect(this.$refs.placeholderNode);
const placeholderReact = getTargetRect(this.$refs.placeholderNode as HTMLElement);
const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);
const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);
if (fixedTop !== undefined) {
@ -218,7 +227,7 @@ const Affix = {
const targetNode = target();
if (targetNode && this.$refs.placeholderNode) {
const targetRect = getTargetRect(targetNode);
const placeholderReact = getTargetRect(this.$refs.placeholderNode);
const placeholderReact = getTargetRect(this.$refs.placeholderNode as HTMLElement);
const fixedTop = getFixedTop(placeholderReact, targetRect, offsetTop);
const fixedBottom = getFixedBottom(placeholderReact, targetRect, offsetBottom);
@ -256,10 +265,9 @@ const Affix = {
</ResizeObserver>
);
},
};
});
/* istanbul ignore next */
Affix.install = function(app) {
Affix.install = function(app: App) {
app.component(Affix.name, Affix);
};

View File

@ -1,22 +1,34 @@
import addEventListener from '../vc-util/Dom/addEventListener';
import { ComponentPublicInstance } from 'vue';
export function getTargetRect(target) {
export type BindElement = HTMLElement | Window | null | undefined;
export type Rect = ClientRect | DOMRect;
export function getTargetRect(target: BindElement): ClientRect {
return target !== window
? target.getBoundingClientRect()
: { top: 0, bottom: window.innerHeight };
? (target as HTMLElement).getBoundingClientRect()
: ({ top: 0, bottom: window.innerHeight } as ClientRect);
}
export function getFixedTop(placeholderReact, targetRect, offsetTop) {
export function getFixedTop(
placeholderReact: Rect,
targetRect: Rect,
offsetTop: number | undefined,
) {
if (offsetTop !== undefined && targetRect.top > placeholderReact.top - offsetTop) {
return offsetTop + targetRect.top + 'px';
return `${offsetTop + targetRect.top}px`;
}
return undefined;
}
export function getFixedBottom(placeholderReact, targetRect, offsetBottom) {
export function getFixedBottom(
placeholderReact: Rect,
targetRect: Rect,
offsetBottom: number | undefined,
) {
if (offsetBottom !== undefined && targetRect.bottom < placeholderReact.bottom + offsetBottom) {
const targetBottomOffset = window.innerHeight - targetRect.bottom;
return offsetBottom + targetBottomOffset + 'px';
return `${offsetBottom + targetBottomOffset}px`;
}
return undefined;
}
@ -32,17 +44,26 @@ const TRIGGER_EVENTS = [
'load',
];
let observerEntities = [];
interface ObserverEntity {
target: HTMLElement | Window;
affixList: ComponentPublicInstance<any>[];
eventHandlers: { [eventName: string]: any };
}
let observerEntities: ObserverEntity[] = [];
export function getObserverEntities() {
// Only used in test env. Can be removed if refactor.
return observerEntities;
}
export function addObserveTarget(target, affix) {
export function addObserveTarget(
target: HTMLElement | Window | null,
affix: ComponentPublicInstance<any>,
): void {
if (!target) return;
let entity = observerEntities.find(item => item.target === target);
let entity: ObserverEntity | undefined = observerEntities.find(item => item.target === target);
if (entity) {
entity.affixList.push(affix);
@ -56,16 +77,16 @@ export function addObserveTarget(target, affix) {
// Add listener
TRIGGER_EVENTS.forEach(eventName => {
entity.eventHandlers[eventName] = addEventListener(target, eventName, () => {
entity.affixList.forEach(targetAffix => {
targetAffix.lazyUpdatePosition();
entity!.eventHandlers[eventName] = addEventListener(target, eventName, () => {
entity!.affixList.forEach(targetAffix => {
(targetAffix as any).lazyUpdatePosition();
});
});
});
}
}
export function removeObserveTarget(affix) {
export function removeObserveTarget(affix: ComponentPublicInstance<any>): void {
const observerEntity = observerEntities.find(oriObserverEntity => {
const hasAffix = oriObserverEntity.affixList.some(item => item === affix);
if (hasAffix) {

View File

@ -2,8 +2,7 @@
"compilerOptions": {
"baseUrl": "./",
"paths": {
"ant-design-vue": ["components/index.tsx"],
"ant-design-vue/es/*": ["components/*"]
"ant-design-vue": ["components/index.tsx"]
},
"strictNullChecks": false,
"strict": true,