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

View File

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

View File

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