【问题标题】:Scrolling to bottom of div without using setTimeout()不使用 setTimeout() 滚动到 div 的底部
【发布时间】:2018-10-22 15:25:58
【问题描述】:

我正在使用 Firebase 创建一个内部实时聊天系统。我拨打这个电话是为了获取所有聊天消息的列表:

firebase.database().ref('chatrooms/'+this.roomkey+'/chats').on('value', resp => {

    this.chats = [];
    this.chats = snapshotToArray(resp);

    setTimeout(() => {
        if(this.content._scroll) { this.content.scrollToBottom(0); }
    }, 1000);

});

在我看来,我有这个 HTML 来循环聊天:

<ion-content>
  <ion-list>
    <ion-item *ngFor="let chat of chats" no-lines>
      <div class="chat-status" text-center *ngIf="chat.type==='join'||chat.type==='exit';else message">
        <span class="chat-date">{{chat.sendDate | date:'short'}}</span>
        <span class="chat-content-center">{{chat.message}}</span>
      </div>
      <ng-template #message>
        <div class="chat-message" text-right *ngIf="chat.user === nickname">
          <div class="right-bubble">
            <span class="msg-name">Me</span>
            <span class="msg-date">{{chat.sendDate | date:'short'}}</span>
            <p text-wrap>{{chat.message}}</p>
          </div>
        </div>
        <div class="chat-message" text-left *ngIf="chat.user !== nickname">
          <div class="left-bubble">
            <span class="msg-name">{{chat.user}}</span>
            <span class="msg-date">{{chat.sendDate | date:'short'}}</span>
            <p text-wrap>{{chat.message}}</p>
          </div>
        </div>
      </ng-template>
    </ion-item>
  </ion-list>
</ion-content>

这是我的相关 CSS:

ion-content {
  height: 100%;
  overflow: hidden;
  .item-md, .item-ios {
    background: none;
  }
}

目前有 30 条聊天消息。它们从 Firebase 加载,然后在一秒钟后,当 setTimeout 完成时,用户会自动滚动到页面底部,以便他们可以看到最新消息。这使得页面加载有点奇怪,一秒钟后跳转到页面底部。

有没有办法用可以实现用户最初看到最新消息的目标来替换超时?也许有一些触发器可以检测到chats 在视图中发生了变化,然后滚动?这似乎比固定的 1 秒暂停要好?

【问题讨论】:

  • 使用 'value' 事件,您正在收听该位置的整个数据集。也许通过使用其他侦听器之一(例如child_addedchild_changed),您可以找到更流畅、对用户更友好的解决方案。

标签: javascript angular firebase firebase-realtime-database


【解决方案1】:

当检测到聊天列表发生变化时,您可以滚动到列表底部:

  • 将模板引用变量与ion-item 元素相关联(例如#chatItems
  • 使用ViewChildren 获取ion-item 元素的QueryList
  • ngAfterViewInit,订阅QueryList.changes 事件
  • 列表更改时滚动到列表底部
<ion-content>
  <ion-list>
    <ion-item #chatItems *ngFor="let chat of chats" no-lines>
      ...
    </ion-item>
  </ion-list>
</ion-content>
export class MyComponent {

  @ViewChildren("chatItems") chatItems: QueryList<any>;

  ngAfterViewInit() {
    this.scrollContentToBottom();
    this.chatItems.changes.subscribe(() => {
      this.scrollContentToBottom();
    });
  }

  scrollContentToBottom() {
    if(this.content._scroll) { 
      this.content.scrollToBottom(0); 
    }
  }
  ...
}

注意:我使用了QueryList&lt;any&gt;,因为我不知道ion-item 组件类型。如果您知道它是什么,您可以放置​​适当的类型。

【讨论】:

  • 嗨,这是一个很大的帮助,谢谢。如果我现在单击按钮打开我的聊天模式窗口,那么我会立即滚动到聊天的底部 - 完美。如果我然后关闭模态窗口,返回我的应用程序,使用另一部手机并发送新消息,在第一台设备上重新打开模态窗口......我没有向下滚动。我仍然在聊天的顶部。我知道 ngAfterViewInit 在第二次打开时被触发。订阅是否只检测第一次更改而不检测后续更改?
  • 第二次打开modal时,新消息是否出现在列表中?如果是这样,可能ngAfterViewInit 中的列表已经完成,因此不会触发changes 事件。我修改了答案以添加默认滚动,以解决这种可能性。
  • 我已根据您的编辑更新了代码。是的,如果我向下滚动但仍然没有变化,新消息会出现在聊天中,在模态窗口的第二次(以及后续)打开时,我没有滚动到底部,我仍然在顶部! (感谢到目前为止的帮助!)
  • 很遗憾,我不能在这里调试它。您能否检查一些console.log 语句,每次打开模式时都会执行ngAfterViewInit,并且触发了changes 回调?我不熟悉离子,所以我不知道this.content._scroll 是否总是true(或者是否需要检查)。
  • 这很奇怪。我添加了一大堆 console.logs,每次都会触发完全相同的事件。目前我已经为 scrollContentToBottom 函数添加了一个 100 毫秒的 setTimeout,这现在可以使聊天模式窗口的每次打开都适当地滚动。 setTimeout(() => { this.content.scrollToBottom(0); }, 100);
猜你喜欢
  • 2015-11-20
  • 2017-04-05
  • 2012-07-13
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多