【问题标题】:ionic 2 + angular 2 : auto scroll to bottom of list / page / chationic 2 + angular 2:自动滚动到列表/页面/聊天的底部
【发布时间】:2016-09-21 18:09:01
【问题描述】:

我正在尝试编写包含“聊天”和“内容”两个部分的页面。我希望那个“聊天”分段页面自动滚动到底部而没有效果。聊天是一个<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。 谢谢 :) 另外,当我转到“内容”部分并返回“聊天”时,我想再次自动滚动聊天。

【问题讨论】:

    标签: javascript angular chat ionic2 autoscroll


    【解决方案1】:

    我是这样做的:

    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 中的重要部分是#content 上的&lt;ion-content&gt;。我将使用#content 标识符在我的chatPage.js 中使用ViewChild 获取对&lt;ion-content&gt; 的引用。

    现在是实际的滚动逻辑:

    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 更新

    当我给出这个答案时,我正在使用 Ionic 2 项目的 JavaScript 版本。随着时间的推移,我切换到了 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
      }
    }
    

    【讨论】:

    • 超时是否修复了 ngFor 更新的延迟?因为没有超时,它会滚动到底部,但会在滚动后添加新行
    • @Ismail 没错。这就是添加超时的原因。
    • this.content 未定义。
    • @smukov 我按照您的步骤操作,但滚动底部为 null
    • 对于那些仍然在this.content 中收到undefined 的人。尝试添加以下内容: 1) 在模板中,将 #content 添加到 ion-content 标记。示例:&lt;ion-content #content&gt; 2) 在控制器中,添加Content 导入,例如:import { Content } from "ion-angular"; 并修改content 声明如下:@ViewChild (Content) private content: Content;。希望这对某人有所帮助。
    【解决方案2】:

    Ionic 有一个选项可以做到这一点并且效果很好:这是 angular 2+ 和 Ionic 最合适的方式。

    从“离子角度”导入{内容}; 导出类 CommentsPage{ @ViewChild(Content) 内容:内容; ionViewWillEnter(): 无效 { this.scrollToBottom(); } 滚动到底部() { 设置超时(()=> { this.content.scrollToBottom(); }); } }

    【讨论】:

    • 离子溶液而不是角溶液,值得更多的支持
    • 当有新消息或内容添加到当前页面时,您将如何调用此方法。我可以在 ionViewWillEnter 上滚动到底部,但是如果我在添加内容时调用它,应用程序就会停止。
    • @fanbondi你在说什么,添加数据的时候直接调用滚动到底部
    【解决方案3】:

    首先,@rinukkusu 的答案是正确的,但它不适用于我的情况,因为 &lt;ion-content&gt;&lt;ion-list&gt; 的父级)有一些错误(离子开发人员正在研究),所以我不得不将该元素与scroll:hidden 放在一起,并在其中创建第二个内容以应用自动滚动。 最后,当页面加载时,我在 construtor 上调用了正确的 (s)css 函数,然后每次用户点击“聊天”段时。

    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);
    }
    

    结论: 该函数被调用两次。当页面被加载(构造函数)并且每次用户回到“聊天”段时。 (click)="autoScroll()"

    我希望这对某人有所帮助。如果您知道更好的方法,请告诉我!几周前我开始使用 Angular2 和 Ionic2,所以这里可能缺少很多概念/基础。

    谢谢:)

    【讨论】:

      【解决方案4】:

      另一种解决方案是“观察”滚动视图中的变化并自动滚动。 即,如果出现消息的地方有新的 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>
      

      (取自Ionic2CLI-Meteor-WhatsApp on Github

      【讨论】:

        【解决方案5】:

        这可以帮助某人,我给出了类似的答案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

        【讨论】:

          【解决方案6】:

          我添加了一个检查以查看用户是否尝试向上滚动。

          <div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
              <div class="..." 
                  *ngFor="..."
                  ...>  
              </div>
          </div>
          

          【讨论】:

            【解决方案7】:

            这是我使用 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();**
            
              }
            

            【讨论】:

              【解决方案8】:

              去做吧:

              public ionViewDidEnter(){
                  this.content.scrollToBottom(300);
              }
              

              【讨论】:

                【解决方案9】:

                如果您的 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>
                

                【讨论】:

                • 很抱歉,但什么也没发生:/
                • 你能再分享一些代码吗?就像那是一个模板还是您希望 javascript 向下滚动的位置?
                • 嘿,对不起,它适用于 codepen,这里的问题是我使用的是 flexbox,所以它不能使用它。我会多尝试一点,然后在几分钟内放弃反馈。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2020-12-22
                • 1970-01-01
                • 2018-09-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-07-27
                相关资源
                最近更新 更多