style: affix & util
parent
c7492a0b59
commit
60e2597f7f
|
@ -0,0 +1,8 @@
|
||||||
|
import UnreachableException from '../unreachableException';
|
||||||
|
|
||||||
|
describe('UnreachableException', () => {
|
||||||
|
it('error thrown matches snapshot', () => {
|
||||||
|
const exception = new UnreachableException('some value');
|
||||||
|
expect(exception.error.message).toMatchInlineSnapshot(`"unreachable case: \\"some value\\""`);
|
||||||
|
});
|
||||||
|
});
|
|
@ -2,8 +2,8 @@ import canUseDom from './canUseDom';
|
||||||
|
|
||||||
export const canUseDocElement = () => canUseDom() && window.document.documentElement;
|
export const canUseDocElement = () => canUseDom() && window.document.documentElement;
|
||||||
|
|
||||||
export const isStyleSupport = (styleName: string | Array<string>): boolean => {
|
const isStyleNameSupport = (styleName: string | string[]): boolean => {
|
||||||
if (canUseDocElement()) {
|
if (canUseDom() && window.document.documentElement) {
|
||||||
const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
|
const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
|
||||||
const { documentElement } = window.document;
|
const { documentElement } = window.document;
|
||||||
|
|
||||||
|
@ -12,6 +12,25 @@ export const isStyleSupport = (styleName: string | Array<string>): boolean => {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isStyleValueSupport = (styleName: string, value: any) => {
|
||||||
|
if (!isStyleNameSupport(styleName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ele = document.createElement('div');
|
||||||
|
const origin = ele.style[styleName];
|
||||||
|
ele.style[styleName] = value;
|
||||||
|
return ele.style[styleName] !== origin;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isStyleSupport(styleName: string | string[], styleValue?: any) {
|
||||||
|
if (!Array.isArray(styleName) && styleValue !== undefined) {
|
||||||
|
return isStyleValueSupport(styleName, styleValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isStyleNameSupport(styleName);
|
||||||
|
}
|
||||||
|
|
||||||
let flexGapSupported: boolean | undefined;
|
let flexGapSupported: boolean | undefined;
|
||||||
export const detectFlexGapSupported = () => {
|
export const detectFlexGapSupported = () => {
|
||||||
if (!canUseDocElement()) {
|
if (!canUseDocElement()) {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
export default class UnreachableException {
|
||||||
|
error: Error;
|
||||||
|
|
||||||
|
constructor(value: never) {
|
||||||
|
this.error = new Error(`unreachable case: ${JSON.stringify(value)}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ export default defineComponent({
|
||||||
name: 'Wave',
|
name: 'Wave',
|
||||||
props: {
|
props: {
|
||||||
insertExtraNode: Boolean,
|
insertExtraNode: Boolean,
|
||||||
|
disabled: Boolean,
|
||||||
},
|
},
|
||||||
setup(props, { slots, expose }) {
|
setup(props, { slots, expose }) {
|
||||||
const instance = getCurrentInstance();
|
const instance = getCurrentInstance();
|
||||||
|
@ -60,10 +61,11 @@ export default defineComponent({
|
||||||
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
|
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
|
||||||
};
|
};
|
||||||
const onClick = (node: HTMLElement, waveColor: string) => {
|
const onClick = (node: HTMLElement, waveColor: string) => {
|
||||||
if (!node || isHidden(node) || node.className.indexOf('-leave') >= 0) {
|
const { insertExtraNode, disabled } = props;
|
||||||
|
if (disabled || !node || isHidden(node) || node.className.indexOf('-leave') >= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { insertExtraNode } = props;
|
|
||||||
extraNode = document.createElement('div');
|
extraNode = document.createElement('div');
|
||||||
extraNode.className = 'ant-click-animating-node';
|
extraNode.className = 'ant-click-animating-node';
|
||||||
const attributeName = getAttributeName();
|
const attributeName = getAttributeName();
|
||||||
|
|
|
@ -23,9 +23,9 @@ Please note that Affix should not cover other content on the page, especially wh
|
||||||
|
|
||||||
### events
|
### events
|
||||||
|
|
||||||
| Events Name | Description | Arguments | Version |
|
| Events Name | Description | Arguments | Version |
|
||||||
| ----------- | ---------------------------------------- | ----------------- | ------- |
|
| ----------- | ---------------------------------------- | --------------------------- | ------- |
|
||||||
| change | Callback for when Affix state is changed | Function(affixed) |
|
| change | Callback for when Affix state is changed | (affixed?: boolean) => void | |
|
||||||
|
|
||||||
**Note:** Children of `Affix` must not have the property `position: absolute`, but you can set `position: absolute` on `Affix` itself:
|
**Note:** Children of `Affix` must not have the property `position: absolute`, but you can set `position: absolute` on `Affix` itself:
|
||||||
|
|
||||||
|
@ -35,8 +35,12 @@ Please note that Affix should not cover other content on the page, especially wh
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### Affix bind container with `target`, sometime move out of container.
|
### When binding container with `target` in Affix, elements sometimes move out of the container.
|
||||||
|
|
||||||
We don't listen window scroll for performance consideration.
|
We only listen to container scroll events for performance consideration. You can add custom listeners if you still want to, like react demo <https://codesandbox.io/s/2xyj5zr85p>
|
||||||
|
|
||||||
Related issues:[#3938](https://github.com/ant-design/ant-design/issues/3938) [#5642](https://github.com/ant-design/ant-design/issues/5642) [#16120](https://github.com/ant-design/ant-design/issues/16120)
|
Related issues:[#3938](https://github.com/ant-design/ant-design/issues/3938) [#5642](https://github.com/ant-design/ant-design/issues/5642) [#16120](https://github.com/ant-design/ant-design/issues/16120)
|
||||||
|
|
||||||
|
### When Affix is used in a horizontal scroll container, the position of the element `left` is incorrect.
|
||||||
|
|
||||||
|
Affix is generally only applicable to areas with one-way scrolling, and only supports usage in vertical scrolling containers. If you want to use it in a horizontal container, you can consider implementing with the native `position: sticky` property.
|
||||||
|
|
|
@ -179,10 +179,7 @@ const Affix = defineComponent({
|
||||||
watch(
|
watch(
|
||||||
() => props.target,
|
() => props.target,
|
||||||
val => {
|
val => {
|
||||||
let newTarget = null;
|
const newTarget = val?.() || null;
|
||||||
if (val) {
|
|
||||||
newTarget = val() || null;
|
|
||||||
}
|
|
||||||
if (state.prevTarget !== newTarget) {
|
if (state.prevTarget !== newTarget) {
|
||||||
removeObserveTarget(currentInstance);
|
removeObserveTarget(currentInstance);
|
||||||
if (newTarget) {
|
if (newTarget) {
|
||||||
|
|
|
@ -19,14 +19,14 @@ cover: https://gw.alipayobjects.com/zos/alicdn/tX6-md4H6/Affix.svg
|
||||||
| 成员 | 说明 | 类型 | 默认值 | 版本 |
|
| 成员 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | number | | |
|
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | number | | |
|
||||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | | |
|
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | 0 | |
|
||||||
| target | 设置 `Affix` 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 | () => HTMLElement | () => window | |
|
| target | 设置 `Affix` 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 | () => HTMLElement | () => window | |
|
||||||
|
|
||||||
### 事件
|
### 事件
|
||||||
|
|
||||||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||||
| -------- | ---------------------------- | ----------------- | ---- | --- |
|
| -------- | ---------------------------- | --------------------------- | ---- | --- |
|
||||||
| change | 固定状态改变时触发的回调函数 | Function(affixed) | 无 | |
|
| change | 固定状态改变时触发的回调函数 | (affixed?: boolean) => void | - | |
|
||||||
|
|
||||||
**注意:**`Affix` 内的元素不要使用绝对定位,如需要绝对定位的效果,可以直接设置 `Affix` 为绝对定位:
|
**注意:**`Affix` 内的元素不要使用绝对定位,如需要绝对定位的效果,可以直接设置 `Affix` 为绝对定位:
|
||||||
|
|
||||||
|
@ -38,6 +38,12 @@ cover: https://gw.alipayobjects.com/zos/alicdn/tX6-md4H6/Affix.svg
|
||||||
|
|
||||||
### Affix 使用 `target` 绑定容器时,元素会跑到容器外。
|
### Affix 使用 `target` 绑定容器时,元素会跑到容器外。
|
||||||
|
|
||||||
从性能角度考虑,我们只监听容器滚动事件。
|
从性能角度考虑,我们只监听容器滚动事件。如果希望任意滚动,你可以在窗体添加滚动监听, 参考 react 版本示例 <https://codesandbox.io/s/2xyj5zr85p>
|
||||||
|
|
||||||
相关 issue:[#3938](https://github.com/ant-design/ant-design/issues/3938) [#5642](https://github.com/ant-design/ant-design/issues/5642) [#16120](https://github.com/ant-design/ant-design/issues/16120)
|
相关 issue:[#3938](https://github.com/ant-design/ant-design/issues/3938) [#5642](https://github.com/ant-design/ant-design/issues/5642) [#16120](https://github.com/ant-design/ant-design/issues/16120)
|
||||||
|
|
||||||
|
### Affix 在水平滚动容器中使用时, 元素 `left` 位置不正确。
|
||||||
|
|
||||||
|
Affix 一般只适用于单向滚动的区域,只支持在垂直滚动容器中使用。如果希望在水平容器中使用,你可以考虑使用 原生 `position: sticky` 实现。
|
||||||
|
|
||||||
|
相关 issue: [#29108](https://github.com/ant-design/ant-design/issues/29108)
|
||||||
|
|
|
@ -3,19 +3,14 @@ import type { ComponentPublicInstance } from 'vue';
|
||||||
import supportsPassive from '../_util/supportsPassive';
|
import supportsPassive from '../_util/supportsPassive';
|
||||||
|
|
||||||
export type BindElement = HTMLElement | Window | null | undefined;
|
export type BindElement = HTMLElement | Window | null | undefined;
|
||||||
export type Rect = ClientRect | DOMRect;
|
|
||||||
|
|
||||||
export function getTargetRect(target: BindElement): ClientRect {
|
export function getTargetRect(target: BindElement): DOMRect {
|
||||||
return target !== window
|
return target !== window
|
||||||
? (target as HTMLElement).getBoundingClientRect()
|
? (target as HTMLElement).getBoundingClientRect()
|
||||||
: ({ top: 0, bottom: window.innerHeight } as ClientRect);
|
: ({ top: 0, bottom: window.innerHeight } as DOMRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFixedTop(
|
export function getFixedTop(placeholderReact: DOMRect, targetRect: DOMRect, offsetTop: number) {
|
||||||
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`;
|
||||||
}
|
}
|
||||||
|
@ -23,9 +18,9 @@ export function getFixedTop(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFixedBottom(
|
export function getFixedBottom(
|
||||||
placeholderReact: Rect,
|
placeholderReact: DOMRect,
|
||||||
targetRect: Rect,
|
targetRect: DOMRect,
|
||||||
offsetBottom: number | undefined,
|
offsetBottom: number,
|
||||||
) {
|
) {
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue