mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 02:31:34 +08:00
fix(segment-view): allow moving the indicator left on scroll without touch
This commit is contained in:
@ -1613,6 +1613,8 @@ ion-segment-content,prop,disabled,boolean,false,false,false
|
||||
ion-segment-view,shadow
|
||||
ion-segment-view,prop,disabled,boolean,false,false,false
|
||||
ion-segment-view,method,setContent,setContent(id: string, smoothScroll?: boolean) => Promise<void>
|
||||
ion-segment-view,event,ionSegmentViewScroll,{ scrollDirection: string; scrollDistance: number; },true
|
||||
ion-segment-view,event,ionSegmentViewScrollEnd,void,true
|
||||
|
||||
ion-select,shadow
|
||||
ion-select,prop,cancelText,string,'Cancel',false,false
|
||||
|
8
core/src/components.d.ts
vendored
8
core/src/components.d.ts
vendored
@ -4443,6 +4443,7 @@ declare global {
|
||||
};
|
||||
interface HTMLIonSegmentViewElementEventMap {
|
||||
"ionSegmentViewScroll": { scrollDirection: string; scrollDistance: number };
|
||||
"ionSegmentViewScrollEnd": void;
|
||||
}
|
||||
interface HTMLIonSegmentViewElement extends Components.IonSegmentView, HTMLStencilElement {
|
||||
addEventListener<K extends keyof HTMLIonSegmentViewElementEventMap>(type: K, listener: (this: HTMLIonSegmentViewElement, ev: IonSegmentViewCustomEvent<HTMLIonSegmentViewElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
@ -7534,7 +7535,14 @@ declare namespace LocalJSX {
|
||||
* If `true`, the segment view cannot be interacted with.
|
||||
*/
|
||||
"disabled"?: boolean;
|
||||
/**
|
||||
* Emitted when the segment view is scrolled.
|
||||
*/
|
||||
"onIonSegmentViewScroll"?: (event: IonSegmentViewCustomEvent<{ scrollDirection: string; scrollDistance: number }>) => void;
|
||||
/**
|
||||
* Emitted when the segment view scroll has ended.
|
||||
*/
|
||||
"onIonSegmentViewScrollEnd"?: (event: IonSegmentViewCustomEvent<void>) => void;
|
||||
}
|
||||
interface IonSelect {
|
||||
/**
|
||||
|
@ -10,8 +10,10 @@ import { Component, Element, Event, Host, Listen, Method, Prop, h } from '@stenc
|
||||
shadow: true,
|
||||
})
|
||||
export class SegmentView implements ComponentInterface {
|
||||
private initialScrollLeft = 0;
|
||||
private initialScrollLeft?: number;
|
||||
private previousScrollLeft = 0;
|
||||
private scrollEndTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
private isTouching = false;
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@ -20,21 +22,31 @@ export class SegmentView implements ComponentInterface {
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
|
||||
/**
|
||||
* Emitted when the segment view is scrolled.
|
||||
*/
|
||||
@Event() ionSegmentViewScroll!: EventEmitter<{ scrollDirection: string; scrollDistance: number }>;
|
||||
|
||||
/**
|
||||
* Emitted when the segment view scroll has ended.
|
||||
*/
|
||||
@Event() ionSegmentViewScrollEnd!: EventEmitter<void>;
|
||||
|
||||
@Listen('scroll')
|
||||
handleScroll(ev: Event) {
|
||||
const { initialScrollLeft, previousScrollLeft } = this;
|
||||
const { scrollLeft, offsetWidth } = ev.target as HTMLElement;
|
||||
|
||||
if (initialScrollLeft === undefined) {
|
||||
this.initialScrollLeft = scrollLeft;
|
||||
}
|
||||
|
||||
const scrollDirection = scrollLeft > previousScrollLeft ? 'right' : 'left';
|
||||
this.previousScrollLeft = scrollLeft;
|
||||
|
||||
let scrollDistance = scrollLeft;
|
||||
|
||||
if (scrollDirection === 'left') {
|
||||
scrollDistance = initialScrollLeft - scrollLeft;
|
||||
}
|
||||
// If the scroll direction is left then we need to calculate where we started and subtract
|
||||
// the current scrollLeft to get the distance scrolled. Otherwise, we use the scrollLeft.
|
||||
const scrollDistance = scrollDirection === 'left' ? initialScrollLeft! - scrollLeft : scrollLeft;
|
||||
|
||||
// Emit the scroll direction and distance
|
||||
this.ionSegmentViewScroll.emit({
|
||||
@ -59,11 +71,54 @@ export class SegmentView implements ComponentInterface {
|
||||
if (segment) {
|
||||
segment.value = segmentButton.value;
|
||||
}
|
||||
|
||||
this.resetScrollEndTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle touch start event to know when the user is actively dragging the segment view.
|
||||
*/
|
||||
@Listen('touchstart')
|
||||
handleTouchStart() {
|
||||
this.initialScrollLeft = this.el.scrollLeft;
|
||||
handleScrollStart() {
|
||||
if (this.scrollEndTimeout) {
|
||||
clearTimeout(this.scrollEndTimeout);
|
||||
this.scrollEndTimeout = null;
|
||||
}
|
||||
|
||||
this.isTouching = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle touch end event to know when the user is no longer dragging the segment view.
|
||||
*/
|
||||
@Listen('touchend')
|
||||
handleTouchEnd() {
|
||||
this.isTouching = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the scroll end detection timer. This is called on every scroll event.
|
||||
*/
|
||||
private resetScrollEndTimeout() {
|
||||
if (this.scrollEndTimeout) {
|
||||
clearTimeout(this.scrollEndTimeout);
|
||||
this.scrollEndTimeout = null;
|
||||
}
|
||||
this.scrollEndTimeout = setTimeout(() => {
|
||||
this.checkForScrollEnd();
|
||||
}, 150);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the scroll has ended and the user is not actively touching.
|
||||
* If both conditions are met, reset the initial scroll position and
|
||||
* emit the scroll end event.
|
||||
*/
|
||||
private checkForScrollEnd() {
|
||||
if (!this.isTouching) {
|
||||
this.ionSegmentViewScrollEnd.emit();
|
||||
this.initialScrollLeft = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2043,14 +2043,20 @@ export class IonSegmentView {
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionSegmentViewScroll']);
|
||||
proxyOutputs(this, this.el, ['ionSegmentViewScroll', 'ionSegmentViewScrollEnd']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export declare interface IonSegmentView extends Components.IonSegmentView {
|
||||
|
||||
/**
|
||||
* Emitted when the segment view is scrolled.
|
||||
*/
|
||||
ionSegmentViewScroll: EventEmitter<CustomEvent<{ scrollDirection: string; scrollDistance: number }>>;
|
||||
/**
|
||||
* Emitted when the segment view scroll has ended.
|
||||
*/
|
||||
ionSegmentViewScrollEnd: EventEmitter<CustomEvent<void>>;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1882,14 +1882,20 @@ export class IonSegmentView {
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionSegmentViewScroll']);
|
||||
proxyOutputs(this, this.el, ['ionSegmentViewScroll', 'ionSegmentViewScrollEnd']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export declare interface IonSegmentView extends Components.IonSegmentView {
|
||||
|
||||
/**
|
||||
* Emitted when the segment view is scrolled.
|
||||
*/
|
||||
ionSegmentViewScroll: EventEmitter<CustomEvent<{ scrollDirection: string; scrollDistance: number }>>;
|
||||
/**
|
||||
* Emitted when the segment view scroll has ended.
|
||||
*/
|
||||
ionSegmentViewScrollEnd: EventEmitter<CustomEvent<void>>;
|
||||
}
|
||||
|
||||
|
||||
|
@ -762,7 +762,8 @@ export const IonSegmentContent = /*@__PURE__*/ defineContainer<JSX.IonSegmentCon
|
||||
|
||||
export const IonSegmentView = /*@__PURE__*/ defineContainer<JSX.IonSegmentView>('ion-segment-view', defineIonSegmentView, [
|
||||
'disabled',
|
||||
'ionSegmentViewScroll'
|
||||
'ionSegmentViewScroll',
|
||||
'ionSegmentViewScrollEnd'
|
||||
]);
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user