ionic 2 + angular 2 : 自动滚动到列表/页面/聊天的底部
ionic 2 + angular 2 : auto scroll to bottom of list / page / chat
我正在尝试对包含两个段 "chat" 和 "content" 的页面进行编码。我希望 "chat" 将页面自动滚动到底部,但没有任何效果。聊天是 <ion-list>
和几个 <ion-item>
.
<ion-list>
<ion-item> item 1 </ion-item>
<ion-item> item 2 </ion-item>
....
<ion-item> item 20 </ion-item>
<ion-item> item 21 </ion-item> <!-- user should see directly this item on bottom of the page -->
</ion-list>
我正在使用 Javascript,而不是 typescript,而且我不想使用 jQuery。
谢谢 :)
另外,当我转到 "content" 部分并返回 "chat" 时,我想再次自动滚动聊天。
如果您的 ion-list
元素具有固定高度,这应该有效。
<ion-list id="item-list">
<ion-item> item 1 </ion-item>
<ion-item> item 2 </ion-item>
[...]
<ion-item> item 20 </ion-item>
<ion-item> item 21 </ion-item>
</ion-list>
[...]
<script>
var itemList = document.getElementById("item-list");
itemList.scrollTop = itemList.scrollHeight
</script>
首先,@rinukkusu 的回答是正确的,但它不适用于我的情况,因为 <ion-content>
(<ion-list>
的父级)有一些错误(ionic 开发人员正在解决这个问题) ),因此我不得不将该元素与 scroll:hidden
一起放置,并在其中创建第二个内容以应用自动滚动。
最后,当页面加载时,我用正确的 (s)css 在 construtor
上调用了该函数,然后每次用户单击 "chat" 段时。
chat.html
<!-- I create the segment and call the `autoScroll()` when users clicks on "chat" -->
<ion-toolbar primary class="toolbar-segment">
<ion-segment light [(ngModel)]="segment">
<ion-segment-button value="chat" (click)="autoScroll()">
Chat
</ion-segment-button>
<ion-segment-button value="profile">
Profile
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<!--I wrote the css inline just as example.
DON'T do it on your project D: -->
<!-- overflow:hidden prevent the ion-content to scroll -->
<ion-content [ngSwitch]="segment" style="overflow: hidden;">
<!-- height: 100% to force scroll if the content overflows the container.
#chat-autoscroll is used by javascript.-->
<div class="content-scroll" id="chat-autoscroll" *ngSwitchWhen="'chat'" style="height: 100%; overflow: scroll">
(... make sure the content is bigger
than the container to see the auto scroll effect ...)
</div>
<!-- here it's just a normal scroll -->
<div *ngSwitchWhen="'profile'" class="content-scroll" style="height: 100%; overflow: auto">
(... content of profile segment ...)
</div>
</ion-content>
chat.js
constructor () {
// when the user opens the page, it shows the "chat" segment as initial value
this.segment = 'chat';
// when page loads, it calls autoScroll();
if (this.segment == 'chat') {
console.log('chat');
this.autoScroll();
};
}
/*Here comes the tricky.
If you don't use setTimeout, the console will say that
#chat-autoscroll doesn't exist in the first call (inside constructor).
This happens because the script runs before the DOM is ready.
I did a workaround with a timeOut of 10ms.
It's enough time to DOM loads and then autoScroll() works fine.
*/
autoScroll() {
setTimeout(function () {
var itemList = document.getElementById("chat-autoscroll");
itemList.scrollTop = itemList.scrollHeight;
}, 10);
}
结论:
该函数被调用两次。当页面加载(构造函数)时以及每次用户返回 "chat" 段时。 (点击)="autoScroll()"
我希望这对某人有所帮助。如果你知道更好的方法,请告诉我!几周前我开始使用 Angular2 和 Ionic2,所以这里可能遗漏了很多 concepts/bases。
谢谢 :)
我是这样做的:
chatPage.html
<ion-content #content padding class="chatPage">
<ion-list no-lines>
<ion-item *ngFor="let msg of messages" >
<chat-bubble [message]="msg"></chat-bubble>
</ion-item>
</ion-list>
</ion-content>
chatPage.html 中的重要部分是 <ion-content>
上的 #content
。我将使用 #content
标识符在我的 chatPage.js 中使用 ViewChild
.[=19= 获取对 <ion-content>
的引用]
现在是实际的滚动逻辑:
chatPage.js
import {Component, ViewChild} from '@angular/core';
@Component({
templateUrl: 'build/pages/chatPage/chatPage.html',
queries: {
content: new ViewChild('content')
}
})
export class ChatPage {
constructor() {
}
//scrolls to bottom whenever the page has loaded
ionViewDidEnter(){
this.content.scrollToBottom(300);//300ms animation speed
}
}
此外,每当我的 chatPage 需要在列表中显示另一条聊天消息(收到新消息或发送新消息)时,我正在使用下面的代码滚动到新的底部:
setTimeout(() => {
this.content.scrollToBottom(300);//300ms animation speed
});
Typescript 更新
当我给出这个答案时,我正在使用 JavaScript 版本的 Ionic 2 项目。随着时间的推移,我切换到 TypeScript,但我忘记更新答案,所以,这是 chatPage.js(ts):
的一个小更新
chatPage.ts
import {Component, ViewChild} from '@angular/core';
@Component({
templateUrl: 'chatPage.html'
})
export class ChatPage {
@ViewChild('content') content:any;
constructor() { }
//scrolls to bottom whenever the page has loaded
ionViewDidEnter(){
this.content.scrollToBottom(300);//300ms animation speed
}
}
就去做吧:
public ionViewDidEnter(){
this.content.scrollToBottom(300);
}
Ionic 有一个选项可以做到这一点并且效果很好:这是 angular 2+ 和 Ionic 最合适的方式。
import { Content } from ‘ionic-angular’;
export class CommentsPage{
@ViewChild(Content) content: Content;
ionViewWillEnter(): void {
this.scrollToBottom();
}
scrollToBottom() {
setTimeout(() => {
this.content.scrollToBottom();
});
}
}
另一个解决方案是"observe"改变滚动视图并自动滚动。
即,如果消息出现的地方有新的 HTML 元素,则滚动到底部。
export class MessagesPage implements OnInit, OnDestroy {
autoScroller: MutationObserver;
ngOnInit() {
this.autoScroller = this.autoScroll();
}
ngOnDestroy() {
this.autoScroller.disconnect();
}
autoScroll(): MutationObserver {
const autoScroller = new MutationObserver(this.scrollDown.bind(this));
autoScroller.observe(this.messagesList, {
childList: true,
subtree: true
});
return autoScroller;
}
scrollDown(): void {
this.scroller.scrollTop = this.scroller.scrollHeight;
this.messageEditor.focus();
}
private get messageEditor(): HTMLInputElement {
return <HTMLInputElement>document.querySelector('ion-input');
}
private get messagesList(): Element {
return document.querySelector('.messages');
}
private get scroller(): Element {
return this.messagesList.querySelector('.scroll-content');
}
}
模板:
<ion-content>
<ion-scroll scrollY="true" class="messages">
<ion-list>
<div *ngFor="let message of messages">
<p [innerHtml]="message.text"></p>
</div>
</ion-list>
</ion-scroll>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-input [(ngModel)]="message" type="text" placeholder="Write a message..." autocomplete="true" spellcheck="true" tappable></ion-input>
<ion-buttons end>
<button ion-button icon-only (click)="sendMessage()">
<ion-icon name="paper-plane"></ion-icon>
</button>
</ion-buttons>
</ion-toolbar>
</ion-footer>
这可能对某人有帮助,我已经给出了类似的答案in Ionic forum。这是在 Ionic 3 中实现的。
我用ngAfterViewChecked()
来实现这个功能。以下是我的代码结构 -
home.html -
<ion-content padding>
<div #scrollMe id="messages-container" style="overflow: auto; height: 100%;">
// All messages elemets. Scroll
</div>
</ion-content>
home.ts -
import { Component,ViewChild, AfterViewChecked, * * } from '@angular/core';
.
.
export class HomePage implements AfterViewChecked{
// used for scrolling the pane
@ViewChild('scrollMe') private myScrollContainer: ElementRef;
ngAfterViewChecked() {
this.scrollToBottom();
}
scrollToBottom(): void {
// method used to enable scrolling
this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
}
}
.scrollTop
和 .scrollHeight
是 JavaScript 属性,see here。
我添加了检查以查看用户是否尝试向上滚动。
<div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
<div class="..."
*ngFor="..."
...>
</div>
</div>
这是我使用 Ionic CLI 5.4.16 的解决方案:
在第 HTML 页中:
<ion-content #content>
在 .TS 页面中:
@ViewChild('content', { static: true }) content: any;
constructor(){}
getInformation(){
//Your Code
..........
//At the end
**this.content.scrollToBottom();**
}
我正在尝试对包含两个段 "chat" 和 "content" 的页面进行编码。我希望 "chat" 将页面自动滚动到底部,但没有任何效果。聊天是 <ion-list>
和几个 <ion-item>
.
<ion-list>
<ion-item> item 1 </ion-item>
<ion-item> item 2 </ion-item>
....
<ion-item> item 20 </ion-item>
<ion-item> item 21 </ion-item> <!-- user should see directly this item on bottom of the page -->
</ion-list>
我正在使用 Javascript,而不是 typescript,而且我不想使用 jQuery。 谢谢 :) 另外,当我转到 "content" 部分并返回 "chat" 时,我想再次自动滚动聊天。
如果您的 ion-list
元素具有固定高度,这应该有效。
<ion-list id="item-list">
<ion-item> item 1 </ion-item>
<ion-item> item 2 </ion-item>
[...]
<ion-item> item 20 </ion-item>
<ion-item> item 21 </ion-item>
</ion-list>
[...]
<script>
var itemList = document.getElementById("item-list");
itemList.scrollTop = itemList.scrollHeight
</script>
首先,@rinukkusu 的回答是正确的,但它不适用于我的情况,因为 <ion-content>
(<ion-list>
的父级)有一些错误(ionic 开发人员正在解决这个问题) ),因此我不得不将该元素与 scroll:hidden
一起放置,并在其中创建第二个内容以应用自动滚动。
最后,当页面加载时,我用正确的 (s)css 在 construtor
上调用了该函数,然后每次用户单击 "chat" 段时。
chat.html
<!-- I create the segment and call the `autoScroll()` when users clicks on "chat" -->
<ion-toolbar primary class="toolbar-segment">
<ion-segment light [(ngModel)]="segment">
<ion-segment-button value="chat" (click)="autoScroll()">
Chat
</ion-segment-button>
<ion-segment-button value="profile">
Profile
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<!--I wrote the css inline just as example.
DON'T do it on your project D: -->
<!-- overflow:hidden prevent the ion-content to scroll -->
<ion-content [ngSwitch]="segment" style="overflow: hidden;">
<!-- height: 100% to force scroll if the content overflows the container.
#chat-autoscroll is used by javascript.-->
<div class="content-scroll" id="chat-autoscroll" *ngSwitchWhen="'chat'" style="height: 100%; overflow: scroll">
(... make sure the content is bigger
than the container to see the auto scroll effect ...)
</div>
<!-- here it's just a normal scroll -->
<div *ngSwitchWhen="'profile'" class="content-scroll" style="height: 100%; overflow: auto">
(... content of profile segment ...)
</div>
</ion-content>
chat.js
constructor () {
// when the user opens the page, it shows the "chat" segment as initial value
this.segment = 'chat';
// when page loads, it calls autoScroll();
if (this.segment == 'chat') {
console.log('chat');
this.autoScroll();
};
}
/*Here comes the tricky.
If you don't use setTimeout, the console will say that
#chat-autoscroll doesn't exist in the first call (inside constructor).
This happens because the script runs before the DOM is ready.
I did a workaround with a timeOut of 10ms.
It's enough time to DOM loads and then autoScroll() works fine.
*/
autoScroll() {
setTimeout(function () {
var itemList = document.getElementById("chat-autoscroll");
itemList.scrollTop = itemList.scrollHeight;
}, 10);
}
结论: 该函数被调用两次。当页面加载(构造函数)时以及每次用户返回 "chat" 段时。 (点击)="autoScroll()"
我希望这对某人有所帮助。如果你知道更好的方法,请告诉我!几周前我开始使用 Angular2 和 Ionic2,所以这里可能遗漏了很多 concepts/bases。
谢谢 :)
我是这样做的:
chatPage.html
<ion-content #content padding class="chatPage">
<ion-list no-lines>
<ion-item *ngFor="let msg of messages" >
<chat-bubble [message]="msg"></chat-bubble>
</ion-item>
</ion-list>
</ion-content>
chatPage.html 中的重要部分是 <ion-content>
上的 #content
。我将使用 #content
标识符在我的 chatPage.js 中使用 ViewChild
.[=19= 获取对 <ion-content>
的引用]
现在是实际的滚动逻辑:
chatPage.js
import {Component, ViewChild} from '@angular/core';
@Component({
templateUrl: 'build/pages/chatPage/chatPage.html',
queries: {
content: new ViewChild('content')
}
})
export class ChatPage {
constructor() {
}
//scrolls to bottom whenever the page has loaded
ionViewDidEnter(){
this.content.scrollToBottom(300);//300ms animation speed
}
}
此外,每当我的 chatPage 需要在列表中显示另一条聊天消息(收到新消息或发送新消息)时,我正在使用下面的代码滚动到新的底部:
setTimeout(() => {
this.content.scrollToBottom(300);//300ms animation speed
});
Typescript 更新
当我给出这个答案时,我正在使用 JavaScript 版本的 Ionic 2 项目。随着时间的推移,我切换到 TypeScript,但我忘记更新答案,所以,这是 chatPage.js(ts):
的一个小更新chatPage.ts
import {Component, ViewChild} from '@angular/core';
@Component({
templateUrl: 'chatPage.html'
})
export class ChatPage {
@ViewChild('content') content:any;
constructor() { }
//scrolls to bottom whenever the page has loaded
ionViewDidEnter(){
this.content.scrollToBottom(300);//300ms animation speed
}
}
就去做吧:
public ionViewDidEnter(){
this.content.scrollToBottom(300);
}
Ionic 有一个选项可以做到这一点并且效果很好:这是 angular 2+ 和 Ionic 最合适的方式。
import { Content } from ‘ionic-angular’; export class CommentsPage{ @ViewChild(Content) content: Content; ionViewWillEnter(): void { this.scrollToBottom(); } scrollToBottom() { setTimeout(() => { this.content.scrollToBottom(); }); } }
另一个解决方案是"observe"改变滚动视图并自动滚动。 即,如果消息出现的地方有新的 HTML 元素,则滚动到底部。
export class MessagesPage implements OnInit, OnDestroy {
autoScroller: MutationObserver;
ngOnInit() {
this.autoScroller = this.autoScroll();
}
ngOnDestroy() {
this.autoScroller.disconnect();
}
autoScroll(): MutationObserver {
const autoScroller = new MutationObserver(this.scrollDown.bind(this));
autoScroller.observe(this.messagesList, {
childList: true,
subtree: true
});
return autoScroller;
}
scrollDown(): void {
this.scroller.scrollTop = this.scroller.scrollHeight;
this.messageEditor.focus();
}
private get messageEditor(): HTMLInputElement {
return <HTMLInputElement>document.querySelector('ion-input');
}
private get messagesList(): Element {
return document.querySelector('.messages');
}
private get scroller(): Element {
return this.messagesList.querySelector('.scroll-content');
}
}
模板:
<ion-content>
<ion-scroll scrollY="true" class="messages">
<ion-list>
<div *ngFor="let message of messages">
<p [innerHtml]="message.text"></p>
</div>
</ion-list>
</ion-scroll>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-input [(ngModel)]="message" type="text" placeholder="Write a message..." autocomplete="true" spellcheck="true" tappable></ion-input>
<ion-buttons end>
<button ion-button icon-only (click)="sendMessage()">
<ion-icon name="paper-plane"></ion-icon>
</button>
</ion-buttons>
</ion-toolbar>
</ion-footer>
这可能对某人有帮助,我已经给出了类似的答案in Ionic forum。这是在 Ionic 3 中实现的。
我用ngAfterViewChecked()
来实现这个功能。以下是我的代码结构 -
home.html -
<ion-content padding>
<div #scrollMe id="messages-container" style="overflow: auto; height: 100%;">
// All messages elemets. Scroll
</div>
</ion-content>
home.ts -
import { Component,ViewChild, AfterViewChecked, * * } from '@angular/core';
.
.
export class HomePage implements AfterViewChecked{
// used for scrolling the pane
@ViewChild('scrollMe') private myScrollContainer: ElementRef;
ngAfterViewChecked() {
this.scrollToBottom();
}
scrollToBottom(): void {
// method used to enable scrolling
this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
}
}
.scrollTop
和 .scrollHeight
是 JavaScript 属性,see here。
我添加了检查以查看用户是否尝试向上滚动。
<div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
<div class="..."
*ngFor="..."
...>
</div>
</div>
这是我使用 Ionic CLI 5.4.16 的解决方案:
在第 HTML 页中:
<ion-content #content>
在 .TS 页面中:
@ViewChild('content', { static: true }) content: any;
constructor(){}
getInformation(){
//Your Code
..........
//At the end
**this.content.scrollToBottom();**
}