Angular2:更改自动滚动指令的检测时间 [英] Angular2: Change detection timing for an auto-scroll directive

查看:24
本文介绍了Angular2:更改自动滚动指令的检测时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

@Directive({选择器:[自动滚动]"})导出类 AutoScroll {@Input() inScrollHeight;@Input() inClientHeight;@HostBinding("scrollTop") outScrollTop;ngOnChanges(changes: {[propName: string]: SimpleChange}) {if (changes["inScrollHeight"] || changes["inClientHeight"]) {this.scroll();}};滚动(){this.outScrollTop = this.inScrollHeight - this.inClientHeight;};}

当我设置了 enableProdMode() 并且 ChangeDetectionStrategy 设置为默认值时,此指令将起作用,但是在开发模式"下时,我得到一个异常.我可以将 ChangeDetectionStrategy 设置为 onPush,在这种情况下不会发生异常但滚动会滞后.

有没有办法更好地构造此代码,以便更新 Dom 然后可以调用 Scroll 函数?我试过 setTimeout() 但这会使延迟变得更糟,尝试使用 ChangeDetectorRef 并订阅可观察对象以触发 markForCheck().使用 ngAfterViewChecked() 会导致浏览器崩溃.

@Component({选择器:聊天显示",模板:`<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>

`,样式:[`.whisper {颜色:玫瑰棕色;}`],指令:[NgClass,AutoScroll],管道:[AsyncPipe,MessageFilterPipe],changeDetection: ChangeDetectionStrategy.OnPush})导出类 ChatDisplay 实现 OnInit {用户名:字符串;@Input() inSelectedTarget: 字符串;@Input() inTargetFilter: 布尔值;@Input() inDirectionFilter: 布尔值;消息:可观察的;构造函数(私有socketService_:SocketService,私有authService_:AuthService){this.username = this.authService_.username;};ngOnInit() {}}

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

<块引用>

例外:表达式 'this.scrollHeight in ChatDisplay@1:40' 在检查后发生了变化.以前的值:'417'.当前值:'420' in [this.scrollHeight in ChatDisplay@1:40]angular2.dev.js (23083,9)

解决方案

我找到了一种方法来解决这个问题,它涉及将聊天显示分成两个独立的组件并使用内容投影.因此,存在从父级到子级的更改流,并且不会在同一组件中具有两个功能,而其中一个会触发另一个功能的更改.我可以使用默认的 changeDetectionStrategy 而不会在开发模式下出现异常.

@Component({选择器:聊天显示",模板:`<自动滚动显示><chat-message *ngFor="#chat of chats | async | messageFilter:username:inSelectedTarget:inTargetFilter:inDirectionFilter" [message]="chat.message" [type]="chat.type"></chat-消息></auto-scroll-display>`,指令:[NgClass、AutoScrollComponent、ChatMessageComponent]、管道:[AsyncPipe,MessageFilterPipe]})导出类 ChatDisplay 实现 OnInit {/* 未更改的代码 */}

自动滚动指令与原始帖子相同,试图找出是否有办法将指令功能组合到组件中.它现在只是充当一个容器.

@Component({选择器:自动滚动显示",模板:`<div #this class="chat-box" [inScrollHeight]="this.scrollHeight" [inClientHeight]="this.clientHeight" autoScroll><ng-content></ng-content>

`,指令:[AutoscrollDirective]})导出类 AutoScrollComponent{}

这是一个包含工作代码的 github 链接,链接.

I've been working on a simple auto-scroll directive for chat-display:

@Directive({
    selector: "[autoScroll]"
})
export class AutoScroll {
    @Input() inScrollHeight;
    @Input() inClientHeight;

    @HostBinding("scrollTop") outScrollTop;

    ngOnChanges(changes: {[propName: string]: SimpleChange}) {
        if (changes["inScrollHeight"] || changes["inClientHeight"]) {
            this.scroll();
        }
    };

    scroll() {
        this.outScrollTop = this.inScrollHeight - this.inClientHeight;
    };
}

This directive will work when I've set enableProdMode() and when the ChangeDetectionStrategy is set to default, but when in "dev mode" I get an exception. I can set the ChangeDetectionStrategy to onPush, in that case the exception doesn't occur but the scroll will lag behind.

Is there a way to better structure this code so that Dom will be updated then the Scroll function can be called? I've tried setTimeout() but that makes the delay worse, tried using ChangeDetectorRef and subscribing to the observable to trigger markForCheck(). Using ngAfterViewChecked() causes browser crashes.

@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() {
    }

}

This is the the exception that is triggered when in dev mode:

EXCEPTION: Expression 'this.scrollHeight in ChatDisplay@1:40' has changed after it was checked. Previous value: '417'. Current value: '420' in [this.scrollHeight in ChatDisplay@1:40] angular2.dev.js (23083,9)

解决方案

I found one way to solve this, it involves dividing the chat display into two separate components and use content projection. So there is a flow of changes from parent to child, and not having two functionalities in the same component with one triggering changes in the other. I can used the default changeDetectionStrategy without getting exceptions in dev mode.

@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 */ }

The auto-scroll directive is identical to original post, was trying to figure out if there was a way to combine the directive functionality into the component. It's just acting as a container now.

@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{ }

Here's a github link with working code, link.

这篇关于Angular2:更改自动滚动指令的检测时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆