如何检测 ion-content 是否有滚动条?
How to detect if ion-content has a scrollbar?
我想在 ion-content 上有或没有滚动条时隐藏或显示元素。更具体地说,我想在没有滚动条时显示一个按钮(以加载列表中的更多项目)并将其隐藏在有滚动条的地方(因此更多项目的加载由 ion-infinite-scroll 完成)。
我的 Ionic 应用程序也将部署到桌面,因此大屏幕用户最初不会看到滚动条,因此不会触发 ion-infinite-scroll。
这是一个演示问题的演示:
home.page.html
<ion-header>
<ion-toolbar>
<ion-title>
Ionic header
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="ion-padding">
<p *ngFor="let item of itemList">{{ item }}</p>
<!-- How to hide this button when ion-content has a scrollbar? -->
<!-- *ngIf="???" -->
<ion-button (click)="incrementItemList(5)">Load more items</ion-button>
</div>
<ion-infinite-scroll (ionInfinite)="loadMoreItems($event)">
<ion-infinite-scroll-content loadingSpinner="crescent"></ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>
Ionic footer
</ion-title>
</ion-toolbar>
</ion-footer>
home.page.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
itemList: string[] = [];
constructor() {}
ionViewWillEnter() {
this.incrementItemList(5);
}
incrementItemList(times: number) {
for (let i = 1; i <= times; i++) {
this.itemList.push(`Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia placeat nam sapiente iusto eligendi`);
}
}
loadMoreItems(event: any) {
setTimeout(() => {
this.incrementItemList(15);
event.target.complete();
}, 1000);
}
}
我正在使用 Ionic 4.5.0 + Angular。
我尝试使用 getScrollElement, scrollHeight, clientHeight, offsetHeight,但没有成功。
有什么想法吗?
更新:我睡了一觉,然后意识到我完全错了。
这是一个工作示例。它检查三个地方以确保它不会错过出现的滚动条:
- 页面加载时
- 添加新内容时
- 当用户滚动时
在我的测试环境中,两次点击添加按钮时正好在屏幕的高度,所以按钮并不总是消失。我添加了 ionScrollEnd
检查以提供捕获它的额外方法。
您可以删除散落在代码周围的 console.log
,我留下它是为了帮助您了解发生了什么。
示例页面:
<ion-header>
<ion-toolbar>
<ion-title>
Scrollbar Test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [scrollEvents]="true" (ionScrollEnd)="onScrollEnd()">
<div class="ion-padding">
<p *ngFor="let item of itemList">{{ item }}</p>
<ion-button *ngIf="!hasScrollbar" (click)="addMoreItemsButtonClick(5)">Load more items</ion-button>
</div>
<ion-infinite-scroll (ionInfinite)="loadMoreItems($event)">
<ion-infinite-scroll-content loadingSpinner="crescent"></ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>
Ionic footer
</ion-title>
</ion-toolbar>
</ion-footer>
示例代码:
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { IonContent } from '@ionic/angular';
@Component({
selector: 'app-scrollheight',
templateUrl: './scrollheight.page.html',
styleUrls: ['./scrollheight.page.scss'],
})
export class ScrollheightPage implements OnInit {
public hasScrollbar: Boolean = false;
@ViewChild(IonContent) private content: IonContent;
itemList: string[] = [];
constructor() { }
ngOnInit() {
// check at startup
this.checkForScrollbar();
}
ionViewWillEnter() {
this.incrementItemList(5);
}
addMoreItemsButtonClick(quantity: number) {
this.incrementItemList(quantity);
// check after pushing to the list
this.checkForScrollbar();
}
onScrollEnd() {
// check after scrolling
this.checkForScrollbar();
}
incrementItemList(times: number) {
for (let i = 1; i <= times; i++) {
this.itemList.push(`Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia placeat nam sapiente iusto eligendi`);
}
}
loadMoreItems(event: any) {
setTimeout(() => {
this.incrementItemList(15);
event.target.complete();
}, 1000);
}
checkForScrollbar() {
this.content.getScrollElement().then((scrollElement) => {
console.log("checking for scroll bar");
console.log({scrollElement});
console.log({scrollHeight: scrollElement.scrollHeight});
console.log({clientHeight: scrollElement.clientHeight});
this.hasScrollbar = (scrollElement.scrollHeight > scrollElement.clientHeight);
console.log({hasScrollBar: this.hasScrollbar});
});
}
}
你能通过从@angular/core导入来使用“NgZone”吗
示例代码在这里。
.ts
import { Component, OnInit, ViewChild, NgZone } from '@angular/core';
@Component({
selector: 'app-selector',
templateUrl: './app.page.html',
styleUrls: ['./app.page.scss'],
})
export class App implements OnInit {
@ViewChild("listingContent") listingContent;
public hasScrollbar: Boolean = false;
public itemList:Array<any> = [];
constructor(private zone: NgZone) {}
scrollHandler(event) {
this.zone.run(()=>{
if (event.detail.scrollTop > (document.documentElement.clientHeight + 1)) {
this.hasScrollbar = true;
} else {
this.hasScrollbar = false;
}
});
}
}
.html
<ion-header no-border></ion-header>
<ion-content #listingContent padding-top (ionScroll)="scrollHandler($event)" scroll-events="true">
<div class="ion-padding">
<p *ngFor="let item of itemList">{{ item }}</p>
<ion-button *ngIf="!hasScrollbar" (click)="addMoreItemsButtonClick(5)">Load more items</ion-button>
</div>
</ion-content>
希望这会有所帮助..
在 rtpHarry 的 post 的帮助下(谢谢!),我终于为这个用例想出了一个合适的解决方案:
home.page.html
<ion-content>
<div class="ion-padding">
<p *ngFor="let item of itemList">{{ item }}</p>
<!--
'*ngIf' removes the button from the DOM and changes the size of 'ion-content' which
is problematic in some scenarios so I toggle the visibility CSS property instead
-->
<ion-button [style.visibility]="hasScrollbar ? 'hidden' : 'visible'" (click)="incrementItemList(5)">Load more items</ion-button>
</div>
<ion-infinite-scroll (ionInfinite)="loadMoreItems($event)">
<ion-infinite-scroll-content loadingSpinner="crescent"></ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
home.page.ts
import { Component, ViewChild, HostListener } from '@angular/core';
import { IonContent } from '@ionic/angular';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
hasScrollbar = false;
itemList: string[] = [];
@ViewChild(IonContent, {static: false}) private content: IonContent;
// checks if there's a scrollbar when the user resizes the window or zooms in/out
@HostListener('window:resize', ['$event'])
onResize() {
this.checkForScrollbar();
}
constructor() {}
ionViewWillEnter() {
this.incrementItemList(5);
}
incrementItemList(times: number) {
for (let i = 1; i <= times; i++) {
this.itemList.push(`Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia placeat nam sapiente iusto eligendi`);
}
this.checkForScrollbar();
}
loadMoreItems(event: any) {
setTimeout(() => {
this.incrementItemList(15);
event.target.complete();
}, 1000);
}
async checkForScrollbar() {
const scrollElement = await this.content.getScrollElement();
this.hasScrollbar = scrollElement.scrollHeight > scrollElement.clientHeight;
}
}
我想在 ion-content 上有或没有滚动条时隐藏或显示元素。更具体地说,我想在没有滚动条时显示一个按钮(以加载列表中的更多项目)并将其隐藏在有滚动条的地方(因此更多项目的加载由 ion-infinite-scroll 完成)。
我的 Ionic 应用程序也将部署到桌面,因此大屏幕用户最初不会看到滚动条,因此不会触发 ion-infinite-scroll。
这是一个演示问题的演示:
home.page.html
<ion-header>
<ion-toolbar>
<ion-title>
Ionic header
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="ion-padding">
<p *ngFor="let item of itemList">{{ item }}</p>
<!-- How to hide this button when ion-content has a scrollbar? -->
<!-- *ngIf="???" -->
<ion-button (click)="incrementItemList(5)">Load more items</ion-button>
</div>
<ion-infinite-scroll (ionInfinite)="loadMoreItems($event)">
<ion-infinite-scroll-content loadingSpinner="crescent"></ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>
Ionic footer
</ion-title>
</ion-toolbar>
</ion-footer>
home.page.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
itemList: string[] = [];
constructor() {}
ionViewWillEnter() {
this.incrementItemList(5);
}
incrementItemList(times: number) {
for (let i = 1; i <= times; i++) {
this.itemList.push(`Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia placeat nam sapiente iusto eligendi`);
}
}
loadMoreItems(event: any) {
setTimeout(() => {
this.incrementItemList(15);
event.target.complete();
}, 1000);
}
}
我正在使用 Ionic 4.5.0 + Angular。
我尝试使用 getScrollElement, scrollHeight, clientHeight, offsetHeight,但没有成功。
有什么想法吗?
更新:我睡了一觉,然后意识到我完全错了。
这是一个工作示例。它检查三个地方以确保它不会错过出现的滚动条:
- 页面加载时
- 添加新内容时
- 当用户滚动时
在我的测试环境中,两次点击添加按钮时正好在屏幕的高度,所以按钮并不总是消失。我添加了 ionScrollEnd
检查以提供捕获它的额外方法。
您可以删除散落在代码周围的 console.log
,我留下它是为了帮助您了解发生了什么。
示例页面:
<ion-header>
<ion-toolbar>
<ion-title>
Scrollbar Test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [scrollEvents]="true" (ionScrollEnd)="onScrollEnd()">
<div class="ion-padding">
<p *ngFor="let item of itemList">{{ item }}</p>
<ion-button *ngIf="!hasScrollbar" (click)="addMoreItemsButtonClick(5)">Load more items</ion-button>
</div>
<ion-infinite-scroll (ionInfinite)="loadMoreItems($event)">
<ion-infinite-scroll-content loadingSpinner="crescent"></ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>
Ionic footer
</ion-title>
</ion-toolbar>
</ion-footer>
示例代码:
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { IonContent } from '@ionic/angular';
@Component({
selector: 'app-scrollheight',
templateUrl: './scrollheight.page.html',
styleUrls: ['./scrollheight.page.scss'],
})
export class ScrollheightPage implements OnInit {
public hasScrollbar: Boolean = false;
@ViewChild(IonContent) private content: IonContent;
itemList: string[] = [];
constructor() { }
ngOnInit() {
// check at startup
this.checkForScrollbar();
}
ionViewWillEnter() {
this.incrementItemList(5);
}
addMoreItemsButtonClick(quantity: number) {
this.incrementItemList(quantity);
// check after pushing to the list
this.checkForScrollbar();
}
onScrollEnd() {
// check after scrolling
this.checkForScrollbar();
}
incrementItemList(times: number) {
for (let i = 1; i <= times; i++) {
this.itemList.push(`Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia placeat nam sapiente iusto eligendi`);
}
}
loadMoreItems(event: any) {
setTimeout(() => {
this.incrementItemList(15);
event.target.complete();
}, 1000);
}
checkForScrollbar() {
this.content.getScrollElement().then((scrollElement) => {
console.log("checking for scroll bar");
console.log({scrollElement});
console.log({scrollHeight: scrollElement.scrollHeight});
console.log({clientHeight: scrollElement.clientHeight});
this.hasScrollbar = (scrollElement.scrollHeight > scrollElement.clientHeight);
console.log({hasScrollBar: this.hasScrollbar});
});
}
}
你能通过从@angular/core导入来使用“NgZone”吗 示例代码在这里。
.ts
import { Component, OnInit, ViewChild, NgZone } from '@angular/core';
@Component({
selector: 'app-selector',
templateUrl: './app.page.html',
styleUrls: ['./app.page.scss'],
})
export class App implements OnInit {
@ViewChild("listingContent") listingContent;
public hasScrollbar: Boolean = false;
public itemList:Array<any> = [];
constructor(private zone: NgZone) {}
scrollHandler(event) {
this.zone.run(()=>{
if (event.detail.scrollTop > (document.documentElement.clientHeight + 1)) {
this.hasScrollbar = true;
} else {
this.hasScrollbar = false;
}
});
}
}
.html
<ion-header no-border></ion-header>
<ion-content #listingContent padding-top (ionScroll)="scrollHandler($event)" scroll-events="true">
<div class="ion-padding">
<p *ngFor="let item of itemList">{{ item }}</p>
<ion-button *ngIf="!hasScrollbar" (click)="addMoreItemsButtonClick(5)">Load more items</ion-button>
</div>
</ion-content>
希望这会有所帮助..
在 rtpHarry 的 post 的帮助下(谢谢!),我终于为这个用例想出了一个合适的解决方案:
home.page.html
<ion-content>
<div class="ion-padding">
<p *ngFor="let item of itemList">{{ item }}</p>
<!--
'*ngIf' removes the button from the DOM and changes the size of 'ion-content' which
is problematic in some scenarios so I toggle the visibility CSS property instead
-->
<ion-button [style.visibility]="hasScrollbar ? 'hidden' : 'visible'" (click)="incrementItemList(5)">Load more items</ion-button>
</div>
<ion-infinite-scroll (ionInfinite)="loadMoreItems($event)">
<ion-infinite-scroll-content loadingSpinner="crescent"></ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
home.page.ts
import { Component, ViewChild, HostListener } from '@angular/core';
import { IonContent } from '@ionic/angular';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
hasScrollbar = false;
itemList: string[] = [];
@ViewChild(IonContent, {static: false}) private content: IonContent;
// checks if there's a scrollbar when the user resizes the window or zooms in/out
@HostListener('window:resize', ['$event'])
onResize() {
this.checkForScrollbar();
}
constructor() {}
ionViewWillEnter() {
this.incrementItemList(5);
}
incrementItemList(times: number) {
for (let i = 1; i <= times; i++) {
this.itemList.push(`Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia placeat nam sapiente iusto eligendi`);
}
this.checkForScrollbar();
}
loadMoreItems(event: any) {
setTimeout(() => {
this.incrementItemList(15);
event.target.complete();
}, 1000);
}
async checkForScrollbar() {
const scrollElement = await this.content.getScrollElement();
this.hasScrollbar = scrollElement.scrollHeight > scrollElement.clientHeight;
}
}