mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
types(IndexBar): use tsx (#8163)
This commit is contained in:
parent
fc7de3658d
commit
57a36967c5
@ -1,14 +1,13 @@
|
|||||||
import { ref, reactive, computed, onMounted } from 'vue';
|
import { ref, reactive, computed, CSSProperties } from 'vue';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { createNamespace } from '../utils';
|
import { createNamespace } from '../utils';
|
||||||
import { BORDER_BOTTOM } from '../utils/constant';
|
import { BORDER_BOTTOM } from '../utils/constant';
|
||||||
import { INDEX_BAR_KEY } from '../index-bar';
|
import { INDEX_BAR_KEY, IndexBarProvide } from '../index-bar';
|
||||||
import { getScrollTop, getRootScrollTop } from '../utils/dom/scroll';
|
import { getScrollTop, getRootScrollTop } from '../utils/dom/scroll';
|
||||||
|
|
||||||
// Composition
|
// Composition
|
||||||
import { useRect, useParent } from '@vant/use';
|
import { useRect, useParent } from '@vant/use';
|
||||||
import { useHeight } from '../composables/use-height';
|
|
||||||
import { useExpose } from '../composables/use-expose';
|
import { useExpose } from '../composables/use-expose';
|
||||||
|
|
||||||
const [createComponent, bem] = createNamespace('index-anchor');
|
const [createComponent, bem] = createNamespace('index-anchor');
|
||||||
@ -28,7 +27,16 @@ export default createComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const root = ref();
|
const root = ref();
|
||||||
const { parent } = useParent(INDEX_BAR_KEY);
|
const { parent } = useParent<IndexBarProvide>(INDEX_BAR_KEY);
|
||||||
|
|
||||||
|
if (!parent) {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
console.error(
|
||||||
|
'[Vant] IndexAnchor must be a child component of IndexBar.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isSticky = () => state.active && parent.props.sticky;
|
const isSticky = () => state.active && parent.props.sticky;
|
||||||
|
|
||||||
@ -42,11 +50,14 @@ export default createComponent({
|
|||||||
width: state.width ? `${state.width}px` : null,
|
width: state.width ? `${state.width}px` : null,
|
||||||
transform: state.top ? `translate3d(0, ${state.top}px, 0)` : null,
|
transform: state.top ? `translate3d(0, ${state.top}px, 0)` : null,
|
||||||
color: highlightColor,
|
color: highlightColor,
|
||||||
};
|
} as CSSProperties;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getRect = (scrollParent, scrollParentRect) => {
|
const getRect = (
|
||||||
|
scrollParent: Window | Element,
|
||||||
|
scrollParentRect: { top: number }
|
||||||
|
) => {
|
||||||
const rootRect = useRect(root);
|
const rootRect = useRect(root);
|
||||||
state.rect.height = rootRect.height;
|
state.rect.height = rootRect.height;
|
||||||
|
|
||||||
@ -60,10 +71,6 @@ export default createComponent({
|
|||||||
return state.rect;
|
return state.rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
state.rect.height = useHeight(root);
|
|
||||||
});
|
|
||||||
|
|
||||||
useExpose({
|
useExpose({
|
||||||
state,
|
state,
|
||||||
getRect,
|
getRect,
|
||||||
@ -75,7 +82,7 @@ export default createComponent({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={root}
|
ref={root}
|
||||||
style={{ height: sticky ? `${state.rect.height}px` : null }}
|
style={{ height: sticky ? `${state.rect.height}px` : undefined }}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={anchorStyle.value}
|
style={anchorStyle.value}
|
@ -1,4 +1,4 @@
|
|||||||
import { ref, computed, watch, nextTick } from 'vue';
|
import { ref, watch, computed, nextTick, PropType, CSSProperties } from 'vue';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import {
|
import {
|
||||||
@ -9,6 +9,7 @@ import {
|
|||||||
createNamespace,
|
createNamespace,
|
||||||
getRootScrollTop,
|
getRootScrollTop,
|
||||||
setRootScrollTop,
|
setRootScrollTop,
|
||||||
|
ComponentInstance,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
|
||||||
// Composition
|
// Composition
|
||||||
@ -23,6 +24,14 @@ import { useExpose } from '../composables/use-expose';
|
|||||||
|
|
||||||
export const INDEX_BAR_KEY = 'vanIndexBar';
|
export const INDEX_BAR_KEY = 'vanIndexBar';
|
||||||
|
|
||||||
|
export type IndexBarProvide = {
|
||||||
|
props: {
|
||||||
|
sticky: boolean;
|
||||||
|
zIndex?: number | string;
|
||||||
|
highlightColor?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
function genAlphabet() {
|
function genAlphabet() {
|
||||||
const indexList = [];
|
const indexList = [];
|
||||||
const charCodeOfA = 'A'.charCodeAt(0);
|
const charCodeOfA = 'A'.charCodeAt(0);
|
||||||
@ -49,7 +58,7 @@ export default createComponent({
|
|||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
indexList: {
|
indexList: {
|
||||||
type: Array,
|
type: Array as PropType<string[]>,
|
||||||
default: genAlphabet,
|
default: genAlphabet,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -57,20 +66,22 @@ export default createComponent({
|
|||||||
emits: ['select', 'change'],
|
emits: ['select', 'change'],
|
||||||
|
|
||||||
setup(props, { emit, slots }) {
|
setup(props, { emit, slots }) {
|
||||||
const root = ref();
|
const root = ref<HTMLElement>();
|
||||||
const activeAnchor = ref();
|
const activeAnchor = ref();
|
||||||
|
|
||||||
const touch = useTouch();
|
const touch = useTouch();
|
||||||
const scrollParent = useScrollParent(root);
|
const scrollParent = useScrollParent(root);
|
||||||
const { children, linkChildren } = useChildren(INDEX_BAR_KEY);
|
const { children, linkChildren } = useChildren<ComponentInstance>(
|
||||||
|
INDEX_BAR_KEY
|
||||||
|
);
|
||||||
|
|
||||||
linkChildren({ props });
|
linkChildren({ props });
|
||||||
|
|
||||||
const sidebarStyle = computed(() => {
|
const sidebarStyle = computed(() => {
|
||||||
if (isDef(props.zIndex)) {
|
if (isDef(props.zIndex)) {
|
||||||
return {
|
return {
|
||||||
zIndex: 1 + props.zIndex,
|
zIndex: +props.zIndex + 1,
|
||||||
};
|
} as CSSProperties;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -78,12 +89,12 @@ export default createComponent({
|
|||||||
if (props.highlightColor) {
|
if (props.highlightColor) {
|
||||||
return {
|
return {
|
||||||
color: props.highlightColor,
|
color: props.highlightColor,
|
||||||
};
|
} as CSSProperties;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getScrollerRect = () => {
|
const getScrollerRect = () => {
|
||||||
if (scrollParent.value.getBoundingClientRect) {
|
if ('getBoundingClientRect' in scrollParent.value!) {
|
||||||
return useRect(scrollParent);
|
return useRect(scrollParent);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -92,7 +103,10 @@ export default createComponent({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getActiveAnchor = (scrollTop, rects) => {
|
const getActiveAnchor = (
|
||||||
|
scrollTop: number,
|
||||||
|
rects: Array<{ top: number; height: number }>
|
||||||
|
) => {
|
||||||
for (let i = children.length - 1; i >= 0; i--) {
|
for (let i = children.length - 1; i >= 0; i--) {
|
||||||
const prevHeight = i > 0 ? rects[i - 1].height : 0;
|
const prevHeight = i > 0 ? rects[i - 1].height : 0;
|
||||||
const reachTop = props.sticky ? prevHeight + props.stickyOffsetTop : 0;
|
const reachTop = props.sticky ? prevHeight + props.stickyOffsetTop : 0;
|
||||||
@ -111,7 +125,7 @@ export default createComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { sticky, indexList } = props;
|
const { sticky, indexList } = props;
|
||||||
const scrollTop = getScrollTop(scrollParent.value);
|
const scrollTop = getScrollTop(scrollParent.value!);
|
||||||
const scrollParentRect = getScrollerRect();
|
const scrollParentRect = getScrollerRect();
|
||||||
|
|
||||||
const rects = children.map((item) =>
|
const rects = children.map((item) =>
|
||||||
@ -172,7 +186,7 @@ export default createComponent({
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
class={bem('index', { active })}
|
class={bem('index', { active })}
|
||||||
style={active ? highlightStyle.value : null}
|
style={active ? highlightStyle.value : undefined}
|
||||||
data-index={index}
|
data-index={index}
|
||||||
>
|
>
|
||||||
{index}
|
{index}
|
||||||
@ -180,7 +194,7 @@ export default createComponent({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const scrollTo = (index) => {
|
const scrollTo = (index: string) => {
|
||||||
if (!index) {
|
if (!index) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -198,29 +212,34 @@ export default createComponent({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const scrollToElement = (element) => {
|
const scrollToElement = (element: HTMLElement) => {
|
||||||
const { index } = element.dataset;
|
const { index } = element.dataset;
|
||||||
scrollTo(index);
|
if (index) {
|
||||||
|
scrollTo(index);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClick = (event) => {
|
const onClickSidebar = (event: MouseEvent) => {
|
||||||
scrollToElement(event.target);
|
scrollToElement(event.target as HTMLElement);
|
||||||
};
|
};
|
||||||
|
|
||||||
let touchActiveIndex;
|
let touchActiveIndex: string;
|
||||||
const onTouchMove = (event) => {
|
|
||||||
|
const onTouchMove = (event: TouchEvent) => {
|
||||||
touch.move(event);
|
touch.move(event);
|
||||||
|
|
||||||
if (touch.isVertical()) {
|
if (touch.isVertical()) {
|
||||||
preventDefault(event);
|
preventDefault(event);
|
||||||
|
|
||||||
const { clientX, clientY } = event.touches[0];
|
const { clientX, clientY } = event.touches[0];
|
||||||
const target = document.elementFromPoint(clientX, clientY);
|
const target = document.elementFromPoint(
|
||||||
|
clientX,
|
||||||
|
clientY
|
||||||
|
) as HTMLElement;
|
||||||
if (target) {
|
if (target) {
|
||||||
const { index } = target.dataset;
|
const { index } = target.dataset;
|
||||||
|
|
||||||
/* istanbul ignore else */
|
if (index && touchActiveIndex !== index) {
|
||||||
if (touchActiveIndex !== index) {
|
|
||||||
touchActiveIndex = index;
|
touchActiveIndex = index;
|
||||||
scrollToElement(target);
|
scrollToElement(target);
|
||||||
}
|
}
|
||||||
@ -235,7 +254,7 @@ export default createComponent({
|
|||||||
<div
|
<div
|
||||||
class={bem('sidebar')}
|
class={bem('sidebar')}
|
||||||
style={sidebarStyle.value}
|
style={sidebarStyle.value}
|
||||||
onClick={onClick}
|
onClick={onClickSidebar}
|
||||||
onTouchstart={touch.start}
|
onTouchstart={touch.start}
|
||||||
onTouchmove={onTouchMove}
|
onTouchmove={onTouchMove}
|
||||||
>
|
>
|
Loading…
x
Reference in New Issue
Block a user