Angular2:更改自动滚动指令的检测时间

时间:2016-03-25 12:29:29

标签: angular angular2-directives angular2-changedetection

我一直在为聊天显示制作一个简单的自动滚动指令:

enableProdMode()

当我设置ChangeDetectionStrategy并且ChangeDetectionStrategy设置为默认值时,此指令将起作用,但当处于“开发模式”时,我会收到异常。我可以将onPush设置为setTimeout(),在这种情况下,不会发生异常,但滚动会滞后。

有没有办法更好地构造这个代码,以便更新Dom,然后可以调用Scroll函数?我已尝试过ChangeDetectorRef,但这会使延迟变得更糟,尝试使用markForCheck()并订阅observable来触发ngAfterViewChecked()。使用@Component({ selector: "chat-display", template: ` <div class="chat-box" #this [inScrollHeight]="this.scrollHeight" [inClientHeight]="this.clientHeight" autoScroll> <p *ngFor="#msg of messages | async | messageFilter:username:inSelectedTarget:inTargetFilter:inDirectionFilter" [ngClass]="msg.type">{{msg.message}}</p> </div> `, styles: [`.whisper { color: rosybrown; }`], directives: [NgClass, AutoScroll], pipes: [AsyncPipe, MessageFilterPipe], changeDetection: ChangeDetectionStrategy.OnPush }) export class ChatDisplay implements OnInit { username: string; @Input() inSelectedTarget: string; @Input() inTargetFilter: boolean; @Input() inDirectionFilter: boolean; messages: Observable<ChatType[]>; constructor(private socketService_: SocketService, private authService_: AuthService) { this.username = this.authService_.username; }; ngOnInit() { } } 会导致浏览器崩溃。

@using projectname.Models

这是在开发模式下触发的异常:

  

EXCEPTION:ChatDisplay @ 1:40'中的表达式'this.scrollHeight'在检查后发生了变化。之前的价值:'417'。当前值:[Chat.isroll @ 1:40中的this.scrollHeight中的'420'       angular2.dev.js(23083,9)

2 个答案:

答案 0 :(得分:2)

我找到了解决此问题的一种方法,它涉及将聊天显示分成两个独立的组件并使用内容投影。因此,从父到子之间存在一系列变化,并且在同一组件中没有两个功能,另一个触发变化。我可以使用默认的changeDetectionStrategy,而不会在开发模式下获得异常。

@Component({
    selector: "chat-display",
    template: `
    <auto-scroll-display>
        <chat-message *ngFor="#chat of chats | async | messageFilter:username:inSelectedTarget:inTargetFilter:inDirectionFilter" [message]="chat.message" [type]="chat.type"></chat-message>
    </auto-scroll-display>
    `,
    directives: [NgClass, AutoScrollComponent, ChatMessageComponent],
    pipes: [AsyncPipe, MessageFilterPipe]
})
export class ChatDisplay implements OnInit { /* unchanged code */ }

自动滚动指令与原始帖子相同,试图弄清楚是否有方法将指令功能组合到组件中。它现在只是作为一个容器。

@Component({
    selector: "auto-scroll-display",
    template: `
    <div #this class="chat-box" [inScrollHeight]="this.scrollHeight" [inClientHeight]="this.clientHeight" autoScroll>
        <ng-content></ng-content>
    </div>
    `,
    directives: [AutoscrollDirective]
})
export class AutoScrollComponent{ }

这是一个带有工作代码的github链接,link

答案 1 :(得分:2)

  

有没有办法更好地构建这个代码,以便更新DOM,然后可以调用Scroll函数?

在调用ngAfterViewChecked()之前应更新DOM。看看这样的东西是否有效:

ngOnChanges(changes: {[propName: string]: SimpleChange}) {
    // detect the change here
    if (changes["inScrollHeight"] || changes["inClientHeight"]) {
        this.scrollAfterDomUpdates = true;
    }
};
ngAfterViewChecked() {
    // but scroll here, after the DOM was updated
    if(this.scrollAfterDomUpdates) {
       this.scrollAfterDomUpdates = false;
       this.scroll();
    }
}

如果这不起作用,请尝试将调用包装在setTimeout中滚动:

    if(this.scrollAfterDomUpdates) {
       this.scrollAfterDomUpdates = false;
       this.setTimeout( _ => this.scroll());
    }