【问题标题】:Ionic 4 Hide Toolbar on scrollIonic 4 滚动时隐藏工具栏
【发布时间】:2019-12-18 23:55:22
【问题描述】:

我正在尝试实现一个指令以在滚动时隐藏工具栏。 我尝试使用本教程: https://medium.com/@gregor.srdic/ionic3-hidding-header-on-footer-on-content-scroll-15ab95b05dc5

这适用于 Ionic 3,但不适用于 Ionic 4。

在下面的代码中我得到了错误:

private adjustElementOnScroll(ev) {
    if (ev) {
        console.log(ev);
        ev.domWrite(() => {
            let scrollTop: number = ev.scrollTop > 0 ? ev.scrollTop : 0;
            let scrolldiff: number = scrollTop - this.lastScrollPosition;
            this.lastScrollPosition = scrollTop;
            let newValue = this.lastValue + scrolldiff;
            newValue = Math.max(0, Math.min(newValue, this.config.maxValue));
            this.renderer.setStyle(this.element.nativeElement, this.config.cssProperty, `-${newValue}px`);
            this.lastValue = newValue;
        });
    }
}

错误:

ev.domWrite is not a function

我查了一下,Ionic 4 中的evCustomEvent,而不是ScrollEvent

有什么建议吗?

【问题讨论】:

    标签: ionic-framework ionic4


    【解决方案1】:

    以上解决方案不再有效。最近几个月,Ionic 4 beta API 发生了很大变化。

    您必须导入 IonContent 而不是 Content

    //scroll-hide.directive.ts
    import { IonContent, DomController } from '@ionic/angular';
    import { Directive, ElementRef, Input, Renderer2, SimpleChanges } from '@angular/core';
    

    在你想使用它的地方导入指令,而不是app.module.ts

    例如在相关模块中,

    //ex: home.module.ts
    import { ScrollHideDirective } from '../../directives/scroll-hide.directive';
    
    @NgModule({
        ...
      declarations: [...,ScrollHideDirective],
        ...
    })
    
    
    then in the ts file,
    
    
    //ex: home.page.ts
    import { ScrollHideConfig } from '../../directives/scroll-hide.directive';
    
    
    export class HomePage implements OnInit {
    
    ...
        footerScrollConfig: ScrollHideConfig = { cssProperty: 'margin-bottom', maxValue: undefined };
        headerScrollConfig: ScrollHideConfig = { cssProperty: 'margin-top', maxValue: 54 };
    ...
    
    }
    

    指令的反转版本

    //ex: scroll-hide.directive.ts    
    
    import { IonContent, DomController } from '@ionic/angular';
    import { Directive, ElementRef, Input, Renderer2, SimpleChanges } from '@angular/core';
    
        @Directive({
          selector: '[scrollHide]'
          })
    export class ScrollHideDirective {
    
      @Input('scrollHide') config: ScrollHideConfig;
      @Input('scrollContent') scrollContent: IonContent;
    
      contentHeight: number;
      scrollHeight: number;
      lastScrollPosition: number;
      lastValue: number = 0;
    
      constructor(private element: ElementRef, private renderer: Renderer2, private  domCtrl: DomController) {
      }
    
      ngOnChanges(changes: SimpleChanges) {
        if(this.scrollContent && this.config) {
          this.scrollContent.scrollEvents = true;
    
          let scrollStartFunc = async (ev) => {
            const el = await this.scrollContent.getScrollElement();
            this.contentHeight = el.offsetHeight;
            this.scrollHeight = el.scrollHeight;
            if (this.config.maxValue === undefined) {
              this.config.maxValue = this.element.nativeElement.offsetHeight;
            }
            this.lastScrollPosition = el.scrollTop;
          };
    
          if(this.scrollContent && this.scrollContent instanceof IonContent) {
            this.scrollContent.ionScrollStart.subscribe(scrollStartFunc);
            this.scrollContent.ionScroll.subscribe(async (ev) => this.adjustElementOnScroll(ev));
            this.scrollContent.ionScrollEnd.subscribe(async (ev) => this.adjustElementOnScroll(ev));
    
          } else if(this.scrollContent instanceof HTMLElement) {
            (this.scrollContent as HTMLElement).addEventListener('ionScrollStart', scrollStartFunc);
            (this.scrollContent as HTMLElement).addEventListener('ionScroll',async (ev) => this.adjustElementOnScroll(ev));
            (this.scrollContent as HTMLElement).addEventListener('ionScrollEnd',async (ev) => this.adjustElementOnScroll(ev));
          }
        }
      }
    
      private adjustElementOnScroll(ev) {
        if (ev) {
          this.domCtrl.write(async () => {
            const el = await this.scrollContent.getScrollElement();
            let scrollTop: number = el.scrollTop > 0 ? el.scrollTop : 0;
            let scrolldiff: number = scrollTop - this.lastScrollPosition;
            this.lastScrollPosition = scrollTop;
            let newValue = this.lastValue + scrolldiff;
            newValue = Math.max(0, Math.min(newValue, this.config.maxValue));
            this.renderer.setStyle(this.element.nativeElement, this.config.cssProperty, `-${newValue}px`);
            this.lastValue = newValue;
          });
        }
      }
    }
    
    export interface ScrollHideConfig {
      cssProperty: string;
      maxValue: number;
    }
    

    html ex:page.html(无变化)

    <ion-header [scrollHide]="headerScrollConfig" [scrollContent]="pageContent">
      ...
    </ion-header>
    
    <ion-content #pageContent fullscreen>
      ...
    </ion-content>
    
    <ion-footer [scrollHide]="footerScrollConfig" [scrollContent]="pageContent">
    ...
    </ion-footer>
    

    希望对你有帮助。

    【讨论】:

    • 知道如何将它与离子标签一起使用吗?
    • 你想隐藏标签吗?无论如何,您可以应用相同的原则。
    • 我无法这样做,因为标签页没有内容或 ion-content 标签看看stackoverflow.com/questions/54307676/…
    • 我看到你有一个关于 filkering 的问题,让我们玩一下footerScrollConfig: ScrollHideConfig = { cssProperty: 'margin-bottom', maxValue: undefined }; ` headerScrollConfig: ScrollHideConfig = { cssProperty: 'margin-top', maxValue: 54 }; 这两个最大值。我将它与标签一起使用。它工作正常。
    • 谢谢你。
    【解决方案2】:

    Ionic 4 的修改指令。

    import { Content, DomController } from '@ionic/angular';
    import { Directive, ElementRef, Input, Renderer2, SimpleChanges } from '@angular/core';
    
    @Directive({
        selector: '[scrollHide]'
    })
    export class ScrollHideDirective {
    
        @Input('scrollHide') config: ScrollHideConfig;
        @Input('scrollContent') scrollContent: Content;
    
        contentHeight: number;
        scrollHeight: number;
        lastScrollPosition: number;
        lastValue: number = 0;
    
        constructor(private element: ElementRef, private renderer: Renderer2, private domCtrl: DomController) {
        }
    
        ngOnChanges(changes: SimpleChanges) {
            if (this.scrollContent && this.config) {
                this.scrollContent.ionScrollStart.subscribe(async (ev) => {
                    const el = await this.scrollContent.getScrollElement();
                    this.contentHeight = el.offsetHeight;
                    this.scrollHeight = el.scrollHeight;    
                    if (this.config.maxValue === undefined) {
                        this.config.maxValue = this.element.nativeElement.offsetHeight;
                    }
                    this.lastScrollPosition = el.scrollTop;
                });
                this.scrollContent.ionScroll.subscribe((ev) => this.adjustElementOnScroll(ev));
                this.scrollContent.ionScrollEnd.subscribe((ev) => this.adjustElementOnScroll(ev));
            }
        }
    
        private adjustElementOnScroll(ev) {
            if (ev) {
                this.domCtrl.write(async () => {
                    const el = await this.scrollContent.getScrollElement();
                    let scrollTop: number = el.scrollTop > 0 ? el.scrollTop : 0;
                    let scrolldiff: number = scrollTop - this.lastScrollPosition;
                    this.lastScrollPosition = scrollTop;
                    let newValue = this.lastValue + scrolldiff;
                    newValue = Math.max(0, Math.min(newValue, this.config.maxValue));
                    this.renderer.setStyle(this.element.nativeElement, this.config.cssProperty, `-${newValue}px`);
                    this.lastValue = newValue;
                });
            }
        }
    }
    export interface ScrollHideConfig {
        cssProperty: string;
        maxValue: number;
    }

    【讨论】:

    • 谢谢!显示/隐藏工作!只是有点不完美。页脚突然消失或显示,应该有一些动画
    • 解决动画问题,需要在主内容上绑定[scrollEvents],设置成true,像&lt;ion-content #content fullscreen [scrollEvents]="true"&gt;这样。
    【解决方案3】:

    Ionic 4 中的事件可能已更改,但您仍然可以从 @ionic/angular 导入 DomController

    import {..., DomController } from "@ionic/angular";
    

    并将其注入构造函数

    constructor(
        // ...
        private domCtrl: DomController
    ) { }
    

    然后像这样使用write() 方法:

    private adjustElementOnScroll(ev) {
        if (ev) {
            this.domCtrl.write(() => {
                // ...
            });
        }
    }
    

    DomController 只是 Ionic 为写入或读取 DOM 的回调创建队列的一种方式,以便在后台使用 window.requestAnimationFrame() 方法。

    欲了解更多信息,请访问:

    1. DomController source code
    2. requestAnimationFrame MDN

    【讨论】:

    • 知道如何将它与离子标签一起使用吗?
    【解决方案4】:

    下面的代码对我有用,上面的代码稍作修正

    import { Content, DomController } from '@ionic/angular';
    import { Directive, ElementRef, Input, Renderer2, SimpleChanges } from '@angular/core';
    
    @Directive({
      selector: '[scrollHide]'
      })
    export class ScrollHideDirective {
    
      @Input('scrollHide') config: ScrollHideConfig;
      @Input('scrollContent') scrollContent: Content;
    
      contentHeight: number;
      scrollHeight: number;
      lastScrollPosition: number;
      lastValue: number = 0;
    
      constructor(private element: ElementRef, private renderer: Renderer2, private domCtrl: DomController) {
      }
    
      ngOnChanges(changes: SimpleChanges) {
        if(this.scrollContent && this.config) {
          this.scrollContent.scrollEvents = true;
    
          let scrollStartFunc = async (ev) => {
            const el = await this.scrollContent.getScrollElement();
            this.contentHeight = el.offsetHeight;
            this.scrollHeight = el.scrollHeight;
            if (this.config.maxValue === undefined) {
              this.config.maxValue = this.element.nativeElement.offsetHeight;
            }
            this.lastScrollPosition = el.scrollTop;
          };
    
          if(this.scrollContent && this.scrollContent instanceof Content) {
            this.scrollContent.ionScrollStart.subscribe(scrollStartFunc);
            this.scrollContent.ionScroll.subscribe(async (ev) => this.adjustElementOnScroll(ev));
            this.scrollContent.ionScrollEnd.subscribe(async (ev) => this.adjustElementOnScroll(ev));
    
          } else if(this.scrollContent instanceof HTMLElement) {
            (this.scrollContent as HTMLElement).addEventListener('ionScrollStart', scrollStartFunc);
            (this.scrollContent as HTMLElement).addEventListener('ionScroll',async (ev) => this.adjustElementOnScroll(ev));
            (this.scrollContent as HTMLElement).addEventListener('ionScrollEnd',async (ev) => this.adjustElementOnScroll(ev));
          }
        }
      }
    
      private adjustElementOnScroll(ev) {
        if (ev) {
          this.domCtrl.write(async () => {
            const el = await this.scrollContent.getScrollElement();
            let scrollTop: number = el.scrollTop > 0 ? el.scrollTop : 0;
            let scrolldiff: number = scrollTop - this.lastScrollPosition;
            this.lastScrollPosition = scrollTop;
            let newValue = this.lastValue + scrolldiff;
            newValue = Math.max(0, Math.min(newValue, this.config.maxValue));
            this.renderer.setStyle(this.element.nativeElement, this.config.cssProperty, `-${newValue}px`);
            this.lastValue = newValue;
          });
        }
      }
    }
    export interface ScrollHideConfig {
      cssProperty: string;
      maxValue: number;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-13
      • 2023-03-17
      • 1970-01-01
      • 2015-12-16
      相关资源
      最近更新 更多